diff --git a/.flake8 b/.flake8 index 9983e283..30cf957b 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,3 @@ [flake8] extend-ignore = E501, E722, E203 +exclude = transaction_pb2* diff --git a/.github/workflows/linter-flake8.yml b/.github/workflows/linter-flake8.yml index d3a5fff3..d9810af6 100644 --- a/.github/workflows/linter-flake8.yml +++ b/.github/workflows/linter-flake8.yml @@ -19,5 +19,5 @@ jobs: pip install -r requirements-dev.txt - name: Lint with flake8 run: | - flake8 multiversx_sdk + flake8 multiversx_sdk --exclude=transaction_pb2* continue-on-error: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f6079628..d969e533 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,3 +29,7 @@ repos: args: - --in-place - --remove-all-unused-imports + - repo: https://github.com/RobertCraigie/pyright-python + rev: v1.1.392 + hooks: + - id: pyright diff --git a/multiversx_sdk/abi/__init__.py b/multiversx_sdk/abi/__init__.py index d3d326bd..c0922a82 100644 --- a/multiversx_sdk/abi/__init__.py +++ b/multiversx_sdk/abi/__init__.py @@ -15,9 +15,16 @@ from multiversx_sdk.abi.option_value import OptionValue from multiversx_sdk.abi.optional_value import OptionalValue from multiversx_sdk.abi.serializer import Serializer -from multiversx_sdk.abi.small_int_values import (I8Value, I16Value, I32Value, - I64Value, U8Value, U16Value, - U32Value, U64Value) +from multiversx_sdk.abi.small_int_values import ( + I8Value, + I16Value, + I32Value, + I64Value, + U8Value, + U16Value, + U32Value, + U64Value, +) from multiversx_sdk.abi.string_value import StringValue from multiversx_sdk.abi.struct_value import StructValue from multiversx_sdk.abi.token_identifier_value import TokenIdentifierValue @@ -27,7 +34,6 @@ __all__ = [ "Abi", "AbiDefinition", - "AddressValue", "ArrayValue", "BigIntValue", @@ -53,7 +59,6 @@ "StructValue", "TokenIdentifierValue", "TupleValue", - "MultiValue", "OptionalValue", "VariadicValues", diff --git a/multiversx_sdk/abi/abi.py b/multiversx_sdk/abi/abi.py index a8adbd45..02ebab54 100644 --- a/multiversx_sdk/abi/abi.py +++ b/multiversx_sdk/abi/abi.py @@ -3,12 +3,15 @@ from types import SimpleNamespace from typing import Any, cast -from multiversx_sdk.abi.abi_definition import (AbiDefinition, - EndpointDefinition, - EnumDefinition, EventDefinition, - EventTopicDefinition, - ParameterDefinition, - StructDefinition) +from multiversx_sdk.abi.abi_definition import ( + AbiDefinition, + EndpointDefinition, + EnumDefinition, + EventDefinition, + EventTopicDefinition, + ParameterDefinition, + StructDefinition, +) from multiversx_sdk.abi.address_value import AddressValue from multiversx_sdk.abi.array_value import ArrayValue from multiversx_sdk.abi.biguint_value import BigUIntValue @@ -21,14 +24,22 @@ from multiversx_sdk.abi.fields import Field from multiversx_sdk.abi.interface import IPayloadHolder from multiversx_sdk.abi.list_value import ListValue +from multiversx_sdk.abi.managed_decimal_signed_value import ManagedDecimalSignedValue from multiversx_sdk.abi.managed_decimal_value import ManagedDecimalValue from multiversx_sdk.abi.multi_value import MultiValue from multiversx_sdk.abi.option_value import OptionValue from multiversx_sdk.abi.optional_value import OptionalValue from multiversx_sdk.abi.serializer import Serializer -from multiversx_sdk.abi.small_int_values import (I8Value, I16Value, I32Value, - I64Value, U8Value, U16Value, - U32Value, U64Value) +from multiversx_sdk.abi.small_int_values import ( + I8Value, + I16Value, + I32Value, + I64Value, + U8Value, + U16Value, + U32Value, + U64Value, +) from multiversx_sdk.abi.string_value import StringValue from multiversx_sdk.abi.struct_value import StructValue from multiversx_sdk.abi.token_identifier_value import TokenIdentifierValue @@ -37,8 +48,6 @@ from multiversx_sdk.abi.type_formula_parser import TypeFormulaParser from multiversx_sdk.abi.variadic_values import VariadicValues -from multiversx_sdk.abi.managed_decimal_signed_value import ManagedDecimalSignedValue - class Abi: def __init__(self, definition: AbiDefinition) -> None: @@ -58,31 +67,26 @@ def __init__(self, definition: AbiDefinition) -> None: self.constructor_prototype = EndpointPrototype( input_parameters=self._create_endpoint_input_prototypes(definition.constructor), - output_parameters=self._create_endpoint_output_prototypes(definition.constructor) + output_parameters=self._create_endpoint_output_prototypes(definition.constructor), ) self.upgrade_constructor_prototype = EndpointPrototype( input_parameters=self._create_endpoint_input_prototypes(definition.upgrade_constructor), - output_parameters=self._create_endpoint_output_prototypes(definition.upgrade_constructor) + output_parameters=self._create_endpoint_output_prototypes(definition.upgrade_constructor), ) for endpoint in definition.endpoints: input_prototype = self._create_endpoint_input_prototypes(endpoint) output_prototype = self._create_endpoint_output_prototypes(endpoint) - endpoint_prototype = EndpointPrototype( - input_parameters=input_prototype, - output_parameters=output_prototype - ) + endpoint_prototype = EndpointPrototype(input_parameters=input_prototype, output_parameters=output_prototype) self.endpoints_prototypes_by_name[endpoint.name] = endpoint_prototype for event in definition.events: prototype = self._create_event_input_prototypes(event) - event_prototype = EventPrototype( - fields=prototype - ) + event_prototype = EventPrototype(fields=prototype) self.events_prototypes_by_name[event.identifier] = event_prototype @@ -101,12 +105,8 @@ def _create_custom_type_prototype(self, name: str) -> Any: def _create_enum_prototype(self, enum_definition: EnumDefinition) -> Any: return EnumValue( - fields_provider=lambda discriminant: self._provide_fields_for_enum_prototype( - discriminant, enum_definition - ), - names_to_discriminants={ - v.name: v.discriminant for v in enum_definition.variants - }, + fields_provider=lambda discriminant: self._provide_fields_for_enum_prototype(discriminant, enum_definition), + names_to_discriminants={v.name: v.discriminant for v in enum_definition.variants}, ) def _create_explicit_enum_prototype(self) -> Any: @@ -127,7 +127,9 @@ def _provide_fields_for_enum_prototype(self, discriminant: int, enum_definition: return fields_prototypes - raise ValueError(f"cannot provide fields from enum {enum_definition.name}: variant with discriminant {discriminant} not found") + raise ValueError( + f"cannot provide fields from enum {enum_definition.name}: variant with discriminant {discriminant} not found" + ) def _create_struct_prototype(self, struct_definition: StructDefinition) -> Any: fields_prototypes: list[Field] = [] @@ -185,9 +187,16 @@ def encode_endpoint_input_parameters(self, endpoint_name: str, values: list[Any] endpoint_prototype = self._get_endpoint_prototype(endpoint_name) return self._do_encode_endpoint_input_parameters(endpoint_name, endpoint_prototype, values) - def _do_encode_endpoint_input_parameters(self, endpoint_name: str, endpoint_prototype: 'EndpointPrototype', values: list[Any]): + def _do_encode_endpoint_input_parameters( + self, + endpoint_name: str, + endpoint_prototype: "EndpointPrototype", + values: list[Any], + ): if len(values) != len(endpoint_prototype.input_parameters): - raise ValueError(f"for {endpoint_name}, invalid value length: expected {len(endpoint_prototype.input_parameters)}, got {len(values)}") + raise ValueError( + f"for {endpoint_name}, invalid value length: expected {len(endpoint_prototype.input_parameters)}, got {len(values)}" + ) input_values = deepcopy(endpoint_prototype.input_parameters) input_values_as_native_object_holders = cast(list[IPayloadHolder], input_values) @@ -249,7 +258,7 @@ def _get_custom_type_prototype(self, type_name: str) -> Any: return type_prototype - def _get_endpoint_prototype(self, endpoint_name: str) -> 'EndpointPrototype': + def _get_endpoint_prototype(self, endpoint_name: str) -> "EndpointPrototype": endpoint_prototype = self.endpoints_prototypes_by_name.get(endpoint_name) if not endpoint_prototype: @@ -257,7 +266,7 @@ def _get_endpoint_prototype(self, endpoint_name: str) -> 'EndpointPrototype': return endpoint_prototype - def _get_event_prototype(self, event_name: str) -> 'EventPrototype': + def _get_event_prototype(self, event_name: str) -> "EventPrototype": event_prototype = self.events_prototypes_by_name.get(event_name) if not event_prototype: @@ -303,7 +312,9 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any: if name == "CodeMetadata": return CodeMetadataValue() if name == "tuple": - return TupleValue([self._create_prototype(type_parameter) for type_parameter in type_formula.type_parameters]) + return TupleValue( + [self._create_prototype(type_parameter) for type_parameter in type_formula.type_parameters] + ) if name == "Option": type_parameter = type_formula.type_parameters[0] return OptionValue(self._create_prototype(type_parameter)) @@ -313,7 +324,10 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any: if name.startswith("array"): type_parameter = type_formula.type_parameters[0] length = int(name[5:]) - return ArrayValue(length=length, item_creator=lambda: self._create_prototype(type_parameter)) + return ArrayValue( + length=length, + item_creator=lambda: self._create_prototype(type_parameter), + ) if name == "optional": # The prototype of an optional is provided a value (the placeholder). type_parameter = type_formula.type_parameters[0] @@ -325,7 +339,9 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any: type_parameter = type_formula.type_parameters[0] return CountedVariadicValues([], item_creator=lambda: self._create_prototype(type_parameter)) if name == "multi": - return MultiValue([self._create_prototype(type_parameter) for type_parameter in type_formula.type_parameters]) + return MultiValue( + [self._create_prototype(type_parameter) for type_parameter in type_formula.type_parameters] + ) if name == "ManagedDecimal": scale = type_formula.type_parameters[0].name @@ -333,8 +349,6 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any: return ManagedDecimalValue(scale=0, is_variable=True) else: return ManagedDecimalValue(scale=int(scale), is_variable=False) - - if name == "ManagedDecimalSigned": scale = type_formula.type_parameters[0].name @@ -348,7 +362,7 @@ def _create_prototype(self, type_formula: TypeFormula) -> Any: return deepcopy(type_prototype) @classmethod - def load(cls, path: Path) -> 'Abi': + def load(cls, path: Path) -> "Abi": definition = AbiDefinition.load(path) return cls(definition) diff --git a/multiversx_sdk/abi/abi_definition.py b/multiversx_sdk/abi/abi_definition.py index 1b50dd0f..65d467e8 100644 --- a/multiversx_sdk/abi/abi_definition.py +++ b/multiversx_sdk/abi/abi_definition.py @@ -4,12 +4,14 @@ class AbiDefinition: - def __init__(self, - constructor: "EndpointDefinition", - upgrade_constructor: "EndpointDefinition", - endpoints: list["EndpointDefinition"], - types: "TypesDefinitions", - events: list["EventDefinition"]) -> None: + def __init__( + self, + constructor: "EndpointDefinition", + upgrade_constructor: "EndpointDefinition", + endpoints: list["EndpointDefinition"], + types: "TypesDefinitions", + events: list["EventDefinition"], + ) -> None: self.constructor = constructor self.upgrade_constructor = upgrade_constructor self.endpoints = endpoints @@ -34,7 +36,7 @@ def from_dict(cls, data: dict[str, Any]) -> "AbiDefinition": upgrade_constructor=upgrade_constructor, endpoints=endpoints, types=types, - events=events + events=events, ) @classmethod @@ -79,15 +81,17 @@ def get_event_definition(self, name: str) -> "EventDefinition": class EndpointDefinition: - def __init__(self, - name: str, - docs: str, - mutability: str, - inputs: list["ParameterDefinition"], - outputs: list["ParameterDefinition"], - payable_in_tokens: list[str], - only_owner: bool, - title: str = "") -> None: + def __init__( + self, + name: str, + docs: str, + mutability: str, + inputs: list["ParameterDefinition"], + outputs: list["ParameterDefinition"], + payable_in_tokens: list[str], + only_owner: bool, + title: str = "", + ) -> None: self.name = name self.docs = docs self.mutability = mutability @@ -110,7 +114,7 @@ def from_dict(cls, data: dict[str, Any]) -> "EndpointDefinition": outputs=outputs, payable_in_tokens=data.get("payableInTokens", []), only_owner=data.get("onlyOwner", False), - title=data.get("title", "") + title=data.get("title", ""), ) def __repr__(self): @@ -127,7 +131,7 @@ def __init__(self) -> None: outputs=[], payable_in_tokens=[], only_owner=False, - title="" + title="", ) def __repr__(self): @@ -150,18 +154,16 @@ def __repr__(self): return f"ParameterDefinition(name={self.name}, type={self.type})" def __eq__(self, value: object) -> bool: - return ( - isinstance(value, ParameterDefinition) - and self.name == value.name - and self.type == value.type - ) + return isinstance(value, ParameterDefinition) and self.name == value.name and self.type == value.type class TypesDefinitions: - def __init__(self, - enums: list["EnumDefinition"], - explicit_enums: list["ExplicitEnumDefinition"], - structs: list["StructDefinition"]) -> None: + def __init__( + self, + enums: list["EnumDefinition"], + explicit_enums: list["ExplicitEnumDefinition"], + structs: list["StructDefinition"], + ) -> None: self.enums: dict[str, EnumDefinition] = {enum.name: enum for enum in enums} self.explicit_enums: dict[str, ExplicitEnumDefinition] = {enum.name: enum for enum in explicit_enums} self.structs: dict[str, StructDefinition] = {struct.name: struct for struct in structs} @@ -184,17 +186,11 @@ def from_dict(cls, data: dict[str, Any]) -> "TypesDefinitions": else: raise ValueError(f"Unsupported kind of custom type: {kind}") - return cls( - enums=enums, - explicit_enums=explicit_enums, - structs=structs - ) + return cls(enums=enums, explicit_enums=explicit_enums, structs=structs) class EnumDefinition: - def __init__(self, - name: str, - variants: list["EnumVariantDefinition"]) -> None: + def __init__(self, name: str, variants: list["EnumVariantDefinition"]) -> None: self.name = name self.variants = variants @@ -202,20 +198,14 @@ def __init__(self, def from_dict(cls, name: str, data: dict[str, Any]) -> "EnumDefinition": variants = [EnumVariantDefinition.from_dict(item) for item in data["variants"]] - return cls( - name=name, - variants=variants - ) + return cls(name=name, variants=variants) def __repr__(self): return f"EnumDefinition(name={self.name})" class EnumVariantDefinition: - def __init__(self, - name: str, - discriminant: int, - fields: list["FieldDefinition"]) -> None: + def __init__(self, name: str, discriminant: int, fields: list["FieldDefinition"]) -> None: self.name = name self.discriminant = discriminant self.fields = fields @@ -227,7 +217,7 @@ def from_dict(cls, data: dict[str, Any]) -> "EnumVariantDefinition": return cls( name=data.get("name", ""), discriminant=data.get("discriminant", 0), - fields=fields + fields=fields, ) def __repr__(self): @@ -235,9 +225,7 @@ def __repr__(self): class ExplicitEnumDefinition: - def __init__(self, - name: str, - variants: list["ExplicitEnumVariantDefinition"]) -> None: + def __init__(self, name: str, variants: list["ExplicitEnumVariantDefinition"]) -> None: self.name = name self.variants = variants @@ -245,10 +233,7 @@ def __init__(self, def from_dict(cls, name: str, data: dict[str, Any]) -> "ExplicitEnumDefinition": variants = [ExplicitEnumVariantDefinition.from_dict(item) for item in data["variants"]] - return cls( - name=name, - variants=variants - ) + return cls(name=name, variants=variants) def __repr__(self): return f"ExplicitEnumDefinition(name={self.name})" @@ -260,18 +245,14 @@ def __init__(self, name: str) -> None: @classmethod def from_dict(cls, data: dict[str, Any]) -> "ExplicitEnumVariantDefinition": - return cls( - name=data.get("name", "") - ) + return cls(name=data.get("name", "")) def __repr__(self): return f"ExplicitEnumVariantDefinition(name={self.name})" class StructDefinition: - def __init__(self, - name: str, - fields: list["FieldDefinition"]) -> None: + def __init__(self, name: str, fields: list["FieldDefinition"]) -> None: self.name = name self.fields = fields @@ -279,20 +260,14 @@ def __init__(self, def from_dict(cls, name: str, data: dict[str, Any]) -> "StructDefinition": fields = [FieldDefinition.from_dict(item) for item in data["fields"]] - return cls( - name=name, - fields=fields - ) + return cls(name=name, fields=fields) def __repr__(self): return f"StructDefinition(name={self.name})" class FieldDefinition: - def __init__(self, - name: str, - description: str, - type: str) -> None: + def __init__(self, name: str, description: str, type: str) -> None: self.name = name self.description = description self.type = type @@ -302,7 +277,7 @@ def from_dict(cls, data: dict[str, Any]) -> "FieldDefinition": return cls( name=data.get("name", ""), description=data.get("description", ""), - type=data.get("type", "") + type=data.get("type", ""), ) def __repr__(self): @@ -310,9 +285,7 @@ def __repr__(self): class EventDefinition: - def __init__(self, - identifier: str, - inputs: list["EventTopicDefinition"]) -> None: + def __init__(self, identifier: str, inputs: list["EventTopicDefinition"]) -> None: self.identifier = identifier self.inputs = inputs @@ -320,31 +293,21 @@ def __init__(self, def from_dict(cls, data: dict[str, Any]) -> "EventDefinition": inputs = [EventTopicDefinition.from_dict(item) for item in data["inputs"]] - return cls( - identifier=data["identifier"], - inputs=inputs - ) + return cls(identifier=data["identifier"], inputs=inputs) def __repr__(self): return f"EventDefinition(identifier={self.identifier})" class EventTopicDefinition: - def __init__(self, - name: str, - type: str, - indexed: bool) -> None: + def __init__(self, name: str, type: str, indexed: bool) -> None: self.name = name self.type = type self.indexed = indexed @classmethod def from_dict(cls, data: dict[str, Any]) -> "EventTopicDefinition": - return cls( - name=data["name"], - type=data["type"], - indexed=data.get("indexed", False) - ) + return cls(name=data["name"], type=data["type"], indexed=data.get("indexed", False)) def __repr__(self): return f"EventTopicDefinition(name={self.name})" diff --git a/multiversx_sdk/abi/abi_test.py b/multiversx_sdk/abi/abi_test.py index 3ae87caa..3501ae7e 100644 --- a/multiversx_sdk/abi/abi_test.py +++ b/multiversx_sdk/abi/abi_test.py @@ -13,6 +13,7 @@ from multiversx_sdk.abi.explicit_enum_value import ExplicitEnumValue from multiversx_sdk.abi.fields import Field from multiversx_sdk.abi.list_value import ListValue +from multiversx_sdk.abi.managed_decimal_value import ManagedDecimalValue from multiversx_sdk.abi.option_value import OptionValue from multiversx_sdk.abi.small_int_values import U32Value, U64Value from multiversx_sdk.abi.string_value import StringValue @@ -20,8 +21,6 @@ from multiversx_sdk.abi.variadic_values import VariadicValues from multiversx_sdk.core.address import Address -from multiversx_sdk.abi.managed_decimal_value import ManagedDecimalValue - testdata = Path(__file__).parent.parent / "testutils" / "testdata" @@ -95,10 +94,7 @@ def test_encode_endpoint_input_parameters_artificial_contract(): abi = Abi.load(testdata / "artificial.abi.json") # All values untyped. - encoded_values = abi.encode_endpoint_input_parameters( - endpoint_name="yellow", - values=[[42, "hello", True]] - ) + encoded_values = abi.encode_endpoint_input_parameters(endpoint_name="yellow", values=[[42, "hello", True]]) assert len(encoded_values) == 3 assert encoded_values[0].hex() == "2a" @@ -111,7 +107,7 @@ def test_encode_endpoint_input_parameters_artificial_contract(): values=[ "hello", StringValue("world"), - ] + ], ) assert encoded_values == [b"hello", b"world"] @@ -122,7 +118,7 @@ def test_encode_endpoint_input_parameters_artificial_contract(): values=[ StringValue("hello"), StringValue("world"), - ] + ], ) assert encoded_values == [b"hello", b"world"] @@ -136,8 +132,8 @@ def test_decode_endpoint_output_parameters_artificial_contract(): encoded_values=[ "UTK-2f80e9".encode(), bytes([0x00]), - bytes.fromhex("0de0b6b3a7640000") - ] + bytes.fromhex("0de0b6b3a7640000"), + ], ) assert decoded_values == [["UTK-2f80e9", 0, 1000000000000000000]] @@ -146,7 +142,7 @@ def test_decode_endpoint_output_parameters_artificial_contract(): endpoint_name="green", encoded_values=[ "completed".encode(), - ] + ], ) assert decoded_values == ["completed"] @@ -157,7 +153,11 @@ def test_encode_endpoint_input_parameters_multisig_propose_batch(): alice = Address.from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") expected_encoded_values = [ - bytes.fromhex("05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743".replace("|", "")) + bytes.fromhex( + "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743".replace( + "|", "" + ) + ) ] # All values untyped, structure as dictionary. @@ -171,15 +171,12 @@ def test_encode_endpoint_input_parameters_multisig_propose_batch(): "to": alice, "egld_amount": 1000000000000000000, "endpoint_name": "example", - "arguments": [ - bytes([0x03, 0x42]), - bytes([0x07, 0x43]) - ], - "opt_gas_limit": 15_000_000 - } + "arguments": [bytes([0x03, 0x42]), bytes([0x07, 0x43])], + "opt_gas_limit": 15_000_000, + }, } ] - ] + ], ) assert encoded_values == expected_encoded_values @@ -195,22 +192,26 @@ def test_encode_endpoint_input_parameters_multisig_propose_batch(): to=alice, egld_amount=1000000000000000000, endpoint_name="example", - arguments=[ - bytes([0x03, 0x42]), - bytes([0x07, 0x43]) - ], - opt_gas_limit=15_000_000 - ) + arguments=[bytes([0x03, 0x42]), bytes([0x07, 0x43])], + opt_gas_limit=15_000_000, + ), } ] - ] + ], ) assert encoded_values == expected_encoded_values # All values untyped, structure as simple object (custom class) class CallActionData: - def __init__(self, to: Address, egld_amount: int, endpoint_name: str, arguments: list[bytes], opt_gas_limit: Optional[int] = None): + def __init__( + self, + to: Address, + egld_amount: int, + endpoint_name: str, + arguments: list[bytes], + opt_gas_limit: Optional[int] = None, + ): self.to = to self.egld_amount = egld_amount self.endpoint_name = endpoint_name @@ -227,15 +228,12 @@ def __init__(self, to: Address, egld_amount: int, endpoint_name: str, arguments: to=alice, egld_amount=1000000000000000000, endpoint_name="example", - arguments=[ - bytes([0x03, 0x42]), - bytes([0x07, 0x43]) - ], - opt_gas_limit=15_000_000 - ) + arguments=[bytes([0x03, 0x42]), bytes([0x07, 0x43])], + opt_gas_limit=15_000_000, + ), } ] - ] + ], ) assert encoded_values == expected_encoded_values @@ -251,15 +249,12 @@ def __init__(self, to: Address, egld_amount: int, endpoint_name: str, arguments: "to": AddressValue.new_from_address(alice), "egld_amount": 1000000000000000000, "endpoint_name": StringValue("example"), - "arguments": [ - bytes([0x03, 0x42]), - bytes([0x07, 0x43]) - ], - "opt_gas_limit": U64Value(15_000_000) - } + "arguments": [bytes([0x03, 0x42]), bytes([0x07, 0x43])], + "opt_gas_limit": U64Value(15_000_000), + }, } ] - ] + ], ) assert encoded_values == expected_encoded_values @@ -273,21 +268,37 @@ def __init__(self, to: Address, egld_amount: int, endpoint_name: str, arguments: EnumValue( discriminant=5, fields=[ - Field("0", StructValue([ - Field("to", AddressValue.new_from_address(alice)), - Field("egld_amount", BigUIntValue(1000000000000000000)), - Field("opt_gas_limit", OptionValue(U64Value(15_000_000))), - Field("endpoint_name", BytesValue(b"example")), - Field("arguments", ListValue([ - BytesValue(bytes([0x03, 0x42])), - BytesValue(bytes([0x07, 0x43])), - ])), - ])), + Field( + "0", + StructValue( + [ + Field("to", AddressValue.new_from_address(alice)), + Field( + "egld_amount", + BigUIntValue(1000000000000000000), + ), + Field( + "opt_gas_limit", + OptionValue(U64Value(15_000_000)), + ), + Field("endpoint_name", BytesValue(b"example")), + Field( + "arguments", + ListValue( + [ + BytesValue(bytes([0x03, 0x42])), + BytesValue(bytes([0x07, 0x43])), + ] + ), + ), + ] + ), + ), ], ) ] ) - ] + ], ) assert encoded_values == expected_encoded_values @@ -296,12 +307,14 @@ def __init__(self, to: Address, egld_amount: int, endpoint_name: str, arguments: def test_decode_endpoint_output_parameters_multisig_get_pending_action_full_info(): abi = Abi.load(testdata / "multisig-full.abi.json") - data_hex = "".join([ - "0000002A", - "0000002A", - "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", - "00000002|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", - ]).replace("|", "") + data_hex = "".join( + [ + "0000002A", + "0000002A", + "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", + "00000002|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", + ] + ).replace("|", "") data = bytes.fromhex(data_hex) [[action_full_info]] = abi.decode_endpoint_output_parameters("getPendingActionFullInfo", [data]) @@ -311,7 +324,10 @@ def test_decode_endpoint_output_parameters_multisig_get_pending_action_full_info assert action_full_info.action_data.__discriminant__ == 5 action_data_0 = getattr(action_full_info.action_data, "0") - assert action_data_0.to == Address.from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key() + assert ( + action_data_0.to + == Address.from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key() + ) assert action_data_0.egld_amount == 1000000000000000000 assert action_data_0.opt_gas_limit == 15000000 assert action_data_0.endpoint_name == b"example" @@ -324,20 +340,20 @@ def test_decode_endpoint_output_parameters_multisig_get_pending_action_full_info def test_managed_decimals(): - abi_definition = AbiDefinition.from_dict({ - "endpoints": [{ - "name": "foo", - "inputs": [ - { - "type": "ManagedDecimal<8>" - }, + abi_definition = AbiDefinition.from_dict( + { + "endpoints": [ { - "type": "ManagedDecimal" + "name": "foo", + "inputs": [ + {"type": "ManagedDecimal<8>"}, + {"type": "ManagedDecimal"}, + ], + "outputs": [], } - ], - "outputs": [] - }] - }) + ] + } + ) abi = Abi(abi_definition) endpoint = abi.endpoints_prototypes_by_name["foo"] @@ -358,26 +374,26 @@ def test_managed_decimals(): def test_encode_decode_managed_decimals(): abi_definition = AbiDefinition.from_dict( - { - "endpoints": [ - { - "name": "dummy", - "inputs": [{"type": "ManagedDecimal<18>"}], - "outputs": [], - }, - { - "name": "foo", - "inputs": [{"name": "x", "type": "ManagedDecimal"}], - "outputs": [{"type": "ManagedDecimalSigned<9>"}], - }, - { - "name": "foobar", - "inputs": [], - "outputs": [{"type": "ManagedDecimal"}], - }, - ] - } - ) + { + "endpoints": [ + { + "name": "dummy", + "inputs": [{"type": "ManagedDecimal<18>"}], + "outputs": [], + }, + { + "name": "foo", + "inputs": [{"name": "x", "type": "ManagedDecimal"}], + "outputs": [{"type": "ManagedDecimalSigned<9>"}], + }, + { + "name": "foobar", + "inputs": [], + "outputs": [{"type": "ManagedDecimal"}], + }, + ] + } + ) abi = Abi(abi_definition) diff --git a/multiversx_sdk/abi/address_value.py b/multiversx_sdk/abi/address_value.py index d4fa4d95..01ac9865 100644 --- a/multiversx_sdk/abi/address_value.py +++ b/multiversx_sdk/abi/address_value.py @@ -10,8 +10,7 @@ class IAddress(Protocol): For internal use only. """ - def get_public_key(self) -> bytes: - ... + def get_public_key(self) -> bytes: ... class AddressValue: diff --git a/multiversx_sdk/abi/address_value_test.py b/multiversx_sdk/abi/address_value_test.py index 031c23f0..cc624689 100644 --- a/multiversx_sdk/abi/address_value_test.py +++ b/multiversx_sdk/abi/address_value_test.py @@ -29,21 +29,13 @@ def test_set_payload_and_get_payload(): # From dict using a bech32 address address = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") value = AddressValue() - value.set_payload( - { - "bech32": address.to_bech32() - } - ) + value.set_payload({"bech32": address.to_bech32()}) assert value.get_payload() == address.get_public_key() # From dict using a hex address address = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") value = AddressValue() - value.set_payload( - { - "hex": address.to_hex() - } - ) + value.set_payload({"hex": address.to_hex()}) assert value.get_payload() == address.get_public_key() value = AddressValue.new_from_address(address) @@ -58,5 +50,8 @@ def test_set_payload_and_get_payload(): AddressValue().set_payload(SimpleNamespace(a=1, b=2, c=3)) # With errors - with pytest.raises(ValueError, match="cannot extract pubkey from dictionary: missing 'bech32' or 'hex' keys"): + with pytest.raises( + ValueError, + match="cannot extract pubkey from dictionary: missing 'bech32' or 'hex' keys", + ): AddressValue().set_payload({}) diff --git a/multiversx_sdk/abi/array_value.py b/multiversx_sdk/abi/array_value.py index 87290210..94130472 100644 --- a/multiversx_sdk/abi/array_value.py +++ b/multiversx_sdk/abi/array_value.py @@ -6,10 +6,12 @@ class ArrayValue: - def __init__(self, - length: int, - items: Optional[list[ISingleValue]] = None, - item_creator: Optional[Callable[[], ISingleValue]] = None) -> None: + def __init__( + self, + length: int, + items: Optional[list[ISingleValue]] = None, + item_creator: Optional[Callable[[], ISingleValue]] = None, + ) -> None: self.length = length self.items = items or [] diff --git a/multiversx_sdk/abi/array_value_test.py b/multiversx_sdk/abi/array_value_test.py index 770e1d28..cd2cf64e 100644 --- a/multiversx_sdk/abi/array_value_test.py +++ b/multiversx_sdk/abi/array_value_test.py @@ -18,7 +18,11 @@ def test_set_payload_and_get_payload(): assert value.get_payload() == [1, 2, 3] # Simple - value = ArrayValue(length=3, items=[BigUIntValue(4), BigUIntValue(5), BigUIntValue(6)], item_creator=lambda: BigUIntValue()) + value = ArrayValue( + length=3, + items=[BigUIntValue(4), BigUIntValue(5), BigUIntValue(6)], + item_creator=lambda: BigUIntValue(), + ) assert value.items == [BigUIntValue(4), BigUIntValue(5), BigUIntValue(6)] assert value.get_payload() == [4, 5, 6] @@ -33,31 +37,30 @@ def test_set_payload_and_get_payload(): assert value.get_payload() == [4, 5, 6] # Nested (with recursion) - value = ArrayValue(length=3, item_creator=lambda: StructValue([ - Field("a", U32Value()), - Field("b", BigUIntValue()) - ])) + value = ArrayValue( + length=3, + item_creator=lambda: StructValue([Field("a", U32Value()), Field("b", BigUIntValue())]), + ) - value.set_payload([ - {"a": 1, "b": 2}, - {"a": 3, "b": 4}, - {"a": 5, "b": 6} - ]) + value.set_payload([{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]) assert value.items == [ StructValue([Field("a", U32Value(1)), Field("b", BigUIntValue(2))]), StructValue([Field("a", U32Value(3)), Field("b", BigUIntValue(4))]), - StructValue([Field("a", U32Value(5)), Field("b", BigUIntValue(6))]) + StructValue([Field("a", U32Value(5)), Field("b", BigUIntValue(6))]), ] assert value.get_payload() == [ SimpleNamespace(a=1, b=2), SimpleNamespace(a=3, b=4), - SimpleNamespace(a=5, b=6) + SimpleNamespace(a=5, b=6), ] # With errors - with pytest.raises(ValueError, match="populating an array from a native object requires the item creator to be set"): + with pytest.raises( + ValueError, + match="populating an array from a native object requires the item creator to be set", + ): value = ArrayValue(length=3) value.set_payload([1, 2, 3]) @@ -67,7 +70,10 @@ def test_set_payload_and_get_payload(): value.set_payload([1, 2, 3]) # With errors - with pytest.raises(ValueError, match="cannot convert native value to list, because of: 'int' object is not iterable"): + with pytest.raises( + ValueError, + match="cannot convert native value to list, because of: 'int' object is not iterable", + ): value = ArrayValue(length=1, item_creator=lambda: U32Value()) value.set_payload(42) diff --git a/multiversx_sdk/abi/bigint_value.py b/multiversx_sdk/abi/bigint_value.py index afeaaf15..5c25e4ea 100644 --- a/multiversx_sdk/abi/bigint_value.py +++ b/multiversx_sdk/abi/bigint_value.py @@ -1,9 +1,7 @@ - import io from typing import Any -from multiversx_sdk.abi.shared import (decode_length, encode_length, - read_bytes_exactly) +from multiversx_sdk.abi.shared import decode_length, encode_length, read_bytes_exactly class BigIntValue: @@ -31,7 +29,7 @@ def _signed_to_bytes(self) -> bytes: value = self.value if value == 0: - return b'' + return b"" length = ((value + (value < 0)).bit_length() + 7 + 1) // 8 data = value.to_bytes(length, byteorder="big", signed=True) diff --git a/multiversx_sdk/abi/biguint_value.py b/multiversx_sdk/abi/biguint_value.py index fcbb6571..ddfebdf5 100644 --- a/multiversx_sdk/abi/biguint_value.py +++ b/multiversx_sdk/abi/biguint_value.py @@ -1,9 +1,7 @@ - import io from typing import Any -from multiversx_sdk.abi.shared import (decode_length, encode_length, - read_bytes_exactly) +from multiversx_sdk.abi.shared import decode_length, encode_length, read_bytes_exactly from multiversx_sdk.core.constants import INTEGER_MAX_NUM_BYTES @@ -32,7 +30,7 @@ def _unsigned_to_bytes(self) -> bytes: value = self.value if value == 0: - return b'' + return b"" data = value.to_bytes(INTEGER_MAX_NUM_BYTES, byteorder="big", signed=False) data = data.lstrip(bytes([0])) diff --git a/multiversx_sdk/abi/bytes_value.py b/multiversx_sdk/abi/bytes_value.py index 173fc5f1..080963b3 100644 --- a/multiversx_sdk/abi/bytes_value.py +++ b/multiversx_sdk/abi/bytes_value.py @@ -1,8 +1,7 @@ import io from typing import Any, cast -from multiversx_sdk.abi.shared import (decode_length, encode_length, - read_bytes_exactly) +from multiversx_sdk.abi.shared import decode_length, encode_length, read_bytes_exactly class BytesValue: diff --git a/multiversx_sdk/abi/bytes_value_test.py b/multiversx_sdk/abi/bytes_value_test.py index 2d83a526..00fd0706 100644 --- a/multiversx_sdk/abi/bytes_value_test.py +++ b/multiversx_sdk/abi/bytes_value_test.py @@ -18,11 +18,7 @@ def test_set_payload_and_get_payload(): # From dictionary value = BytesValue() - value.set_payload( - { - "hex": "68656c6c6f" - } - ) + value.set_payload({"hex": "68656c6c6f"}) assert value.get_payload() == b"hello" # With errors diff --git a/multiversx_sdk/abi/code_metadata_value.py b/multiversx_sdk/abi/code_metadata_value.py index be17ea7e..8c2b95f4 100644 --- a/multiversx_sdk/abi/code_metadata_value.py +++ b/multiversx_sdk/abi/code_metadata_value.py @@ -2,8 +2,7 @@ from typing import Any from multiversx_sdk.abi.shared import read_bytes_exactly -from multiversx_sdk.core.code_metadata import (CODE_METADATA_LENGTH, - CodeMetadata) +from multiversx_sdk.core.code_metadata import CODE_METADATA_LENGTH, CodeMetadata class CodeMetadataValue: @@ -36,7 +35,9 @@ def set_payload(self, value: Any): elif isinstance(value, dict): self.value = self._extract_value_from_dict(value) else: - raise ValueError(f"cannot set payload for code metadata (should be either a CodeMetadata, bytes or dict, but got: {type(value)})") + raise ValueError( + f"cannot set payload for code metadata (should be either a CodeMetadata, bytes or dict, but got: {type(value)})" + ) def _extract_value_from_dict(self, value: dict[str, str]) -> bytes: hex_value = value.get("hex", None) diff --git a/multiversx_sdk/abi/code_metadata_value_test.py b/multiversx_sdk/abi/code_metadata_value_test.py index 9e52e3ec..ed6968b3 100644 --- a/multiversx_sdk/abi/code_metadata_value_test.py +++ b/multiversx_sdk/abi/code_metadata_value_test.py @@ -10,7 +10,9 @@ def test_new_from_code_metadata(): value = CodeMetadataValue.new_from_code_metadata(CodeMetadata()) assert value.get_payload() == bytes([0x05, 0x00]) - value = CodeMetadataValue.new_from_code_metadata(CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True)) + value = CodeMetadataValue.new_from_code_metadata( + CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True) + ) assert value.get_payload() == bytes([0x05, 0x06]) @@ -27,13 +29,16 @@ def test_set_payload_and_get_payload(): # From dictionary value = CodeMetadataValue() - value.set_payload({ - "hex": "0500" - }) + value.set_payload({"hex": "0500"}) assert value.get_payload() == bytes([0x05, 0x00]) # With errors - with pytest.raises(ValueError, match=re.escape("cannot set payload for code metadata (should be either a CodeMetadata, bytes or dict, but got: )")): + with pytest.raises( + ValueError, + match=re.escape( + "cannot set payload for code metadata (should be either a CodeMetadata, bytes or dict, but got: )" + ), + ): CodeMetadataValue().set_payload(5) with pytest.raises(ValueError, match="code metadata buffer has length 4, expected 2"): diff --git a/multiversx_sdk/abi/codec.py b/multiversx_sdk/abi/codec.py index d8eaf63c..9644c253 100644 --- a/multiversx_sdk/abi/codec.py +++ b/multiversx_sdk/abi/codec.py @@ -1,4 +1,3 @@ - import io from multiversx_sdk.abi.interface import ISingleValue diff --git a/multiversx_sdk/abi/counted_variadic_values.py b/multiversx_sdk/abi/counted_variadic_values.py index 00571d67..8d486ca0 100644 --- a/multiversx_sdk/abi/counted_variadic_values.py +++ b/multiversx_sdk/abi/counted_variadic_values.py @@ -6,9 +6,11 @@ class CountedVariadicValues(IPayloadHolder): - def __init__(self, - items: Optional[list[Union[ISingleValue, MultiValue]]] = None, - item_creator: Optional[Callable[[], Union[ISingleValue, MultiValue]]] = None) -> None: + def __init__( + self, + items: Optional[list[Union[ISingleValue, MultiValue]]] = None, + item_creator: Optional[Callable[[], Union[ISingleValue, MultiValue]]] = None, + ) -> None: self.items = items or [] self.length = len(self.items) diff --git a/multiversx_sdk/abi/counted_variadic_values_test.py b/multiversx_sdk/abi/counted_variadic_values_test.py index defc9f66..102378e7 100644 --- a/multiversx_sdk/abi/counted_variadic_values_test.py +++ b/multiversx_sdk/abi/counted_variadic_values_test.py @@ -24,13 +24,16 @@ def test_set_payload_and_get_payload(): assert values.length == 2 assert values.items == [ MultiValue([U32Value(42), StringValue("hello")]), - MultiValue([U32Value(43), StringValue("world")]) + MultiValue([U32Value(43), StringValue("world")]), ] assert values.get_payload() == [[42, "hello"], [43, "world"]] # With errors - with pytest.raises(ValueError, match="populating variadic values from a native object requires the item creator to be set"): + with pytest.raises( + ValueError, + match="populating variadic values from a native object requires the item creator to be set", + ): CountedVariadicValues().set_payload([1, 2, 3]) # With errors diff --git a/multiversx_sdk/abi/enum_value.py b/multiversx_sdk/abi/enum_value.py index 697ffeab..ee151a7f 100644 --- a/multiversx_sdk/abi/enum_value.py +++ b/multiversx_sdk/abi/enum_value.py @@ -21,11 +21,13 @@ class EnumValue: - def __init__(self, - discriminant: int = 0, - fields: Optional[list[Field]] = None, - fields_provider: Optional[Callable[[int], list[Field]]] = None, - names_to_discriminants: Optional[dict[str, int]] = None) -> None: + def __init__( + self, + discriminant: int = 0, + fields: Optional[list[Field]] = None, + fields_provider: Optional[Callable[[int], list[Field]]] = None, + names_to_discriminants: Optional[dict[str, int]] = None, + ) -> None: self.discriminant = discriminant self.fields = fields or [] self.fields_provider = fields_provider @@ -65,7 +67,9 @@ def decode_top_level(self, data: bytes): def convert_name_to_discriminant(self, variant_name: str) -> int: if self.names_to_discriminants is None: - raise ValueError("converting a variant name to its discriminant requires the names to discriminants dict to be set") + raise ValueError( + "converting a variant name to its discriminant requires the names to discriminants dict to be set" + ) return self.names_to_discriminants[variant_name] def set_payload(self, value: Any): @@ -74,7 +78,9 @@ def set_payload(self, value: Any): if isinstance(value, int): if self.fields_provider(value): - raise ValueError("for enums, if the native object is a mere integer, it must be the discriminant, and the corresponding enum variant must have no fields") + raise ValueError( + "for enums, if the native object is a mere integer, it must be the discriminant, and the corresponding enum variant must have no fields" + ) self.discriminant = value return @@ -82,7 +88,9 @@ def set_payload(self, value: Any): if isinstance(value, str): discriminant = self.convert_name_to_discriminant(value) if self.fields_provider(discriminant): - raise ValueError("for enums, if the native object is a mere string, it must be the name of the variant, and the corresponding enum variant must have no fields") + raise ValueError( + "for enums, if the native object is a mere string, it must be the name of the variant, and the corresponding enum variant must have no fields" + ) self.discriminant = discriminant return @@ -139,11 +147,7 @@ def get_payload(self) -> Any: return obj def __eq__(self, other: Any) -> bool: - return ( - isinstance(other, EnumValue) - and self.discriminant == other.discriminant - and self.fields == other.fields - ) + return isinstance(other, EnumValue) and self.discriminant == other.discriminant and self.fields == other.fields def __iter__(self): yield (ENUM_DISCRIMINANT_FIELD_NAME, self.discriminant) diff --git a/multiversx_sdk/abi/enum_value_test.py b/multiversx_sdk/abi/enum_value_test.py index 11dfd6b2..0c98ac80 100644 --- a/multiversx_sdk/abi/enum_value_test.py +++ b/multiversx_sdk/abi/enum_value_test.py @@ -24,14 +24,10 @@ def test_set_payload_and_get_payload(): "for enums, the native object (when it's a dictionary) must contain the special field '__discriminant__' or '__name__'" ), ): - EnumValue( - fields_provider=lambda discriminant: [] - ).set_payload({}) + EnumValue(fields_provider=lambda discriminant: []).set_payload({}) # Simple - value = EnumValue( - fields_provider=lambda discriminant: [] - ) + value = EnumValue(fields_provider=lambda discriminant: []) value.set_payload(42) assert value.discriminant == 42 assert value.get_payload() == SimpleNamespace(__discriminant__=42) @@ -98,9 +94,7 @@ def test_set_payload_and_get_payload_using_names(): EnumValue(fields_provider=lambda discriminant: []).set_payload("TypeA") # Simple - value = EnumValue( - fields_provider=lambda discriminant: [], names_to_discriminants={"TypeB": 42} - ) + value = EnumValue(fields_provider=lambda discriminant: [], names_to_discriminants={"TypeB": 42}) value.set_payload("TypeB") assert value.discriminant == 42 assert value.get_payload() == SimpleNamespace(__discriminant__=42) diff --git a/multiversx_sdk/abi/fields.py b/multiversx_sdk/abi/fields.py index ff21c9c5..f1260bcf 100644 --- a/multiversx_sdk/abi/fields.py +++ b/multiversx_sdk/abi/fields.py @@ -50,7 +50,9 @@ def set_fields_from_dictionary(fields: list[Field], dictionary: dict[str, Any]): def set_fields_from_list(fields: list[Field], items: list[Any]): if len(fields) != len(items): - raise ValueError(f"the number of fields ({len(fields)}) does not match the number of provided items ({len(items)})") + raise ValueError( + f"the number of fields ({len(fields)}) does not match the number of provided items ({len(items)})" + ) for index, field in enumerate(fields): field_payload = items[index] diff --git a/multiversx_sdk/abi/fields_test.py b/multiversx_sdk/abi/fields_test.py index fe63ee8b..aa6243f4 100644 --- a/multiversx_sdk/abi/fields_test.py +++ b/multiversx_sdk/abi/fields_test.py @@ -2,18 +2,17 @@ import pytest -from multiversx_sdk.abi.fields import (Field, set_fields_from_dictionary, - set_fields_from_list) +from multiversx_sdk.abi.fields import ( + Field, + set_fields_from_dictionary, + set_fields_from_list, +) from multiversx_sdk.abi.small_int_values import U32Value def test_set_fields_from_dictionary(): # Basic - fields = [ - Field("a", U32Value()), - Field("b", U32Value()), - Field("c", U32Value()) - ] + fields = [Field("a", U32Value()), Field("b", U32Value()), Field("c", U32Value())] set_fields_from_dictionary(fields, {"a": 1, "b": 2, "c": 3}) @@ -26,17 +25,18 @@ def test_set_fields_from_dictionary(): set_fields_from_dictionary(fields, {"a": 1, "b": 2}) # Bad type - with pytest.raises(ValueError, match=re.escape("cannot set payload for field 'a', because of: invalid literal for int() with base 10: 'foobar'")): + with pytest.raises( + ValueError, + match=re.escape( + "cannot set payload for field 'a', because of: invalid literal for int() with base 10: 'foobar'" + ), + ): set_fields_from_dictionary(fields, {"a": "foobar", "b": 2, "c": 3}) def test_set_fields_from_list(): # Basic - fields = [ - Field("a", U32Value()), - Field("b", U32Value()), - Field("c", U32Value()) - ] + fields = [Field("a", U32Value()), Field("b", U32Value()), Field("c", U32Value())] set_fields_from_list(fields, [1, 2, 3]) @@ -45,9 +45,17 @@ def test_set_fields_from_list(): assert fields[2].value.get_payload() == 3 # Missing field - with pytest.raises(ValueError, match=re.escape("the number of fields (3) does not match the number of provided items (2)")): + with pytest.raises( + ValueError, + match=re.escape("the number of fields (3) does not match the number of provided items (2)"), + ): set_fields_from_list(fields, [1, 2]) # Bad type - with pytest.raises(ValueError, match=re.escape("cannot set payload for field 'a', because of: invalid literal for int() with base 10: 'foobar'")): + with pytest.raises( + ValueError, + match=re.escape( + "cannot set payload for field 'a', because of: invalid literal for int() with base 10: 'foobar'" + ), + ): set_fields_from_list(fields, ["foobar", 2, 3]) diff --git a/multiversx_sdk/abi/interface.py b/multiversx_sdk/abi/interface.py index faedfbfa..432f610b 100644 --- a/multiversx_sdk/abi/interface.py +++ b/multiversx_sdk/abi/interface.py @@ -3,23 +3,17 @@ class IPayloadHolder(Protocol): - def set_payload(self, value: Any): - ... + def set_payload(self, value: Any): ... - def get_payload(self) -> Any: - ... + def get_payload(self) -> Any: ... @runtime_checkable class ISingleValue(IPayloadHolder, Protocol): - def encode_nested(self, writer: io.BytesIO): - ... + def encode_nested(self, writer: io.BytesIO): ... - def encode_top_level(self, writer: io.BytesIO): - ... + def encode_top_level(self, writer: io.BytesIO): ... - def decode_nested(self, reader: io.BytesIO): - ... + def decode_nested(self, reader: io.BytesIO): ... - def decode_top_level(self, data: bytes): - ... + def decode_top_level(self, data: bytes): ... diff --git a/multiversx_sdk/abi/list_value.py b/multiversx_sdk/abi/list_value.py index 9c173178..ce80bdaf 100644 --- a/multiversx_sdk/abi/list_value.py +++ b/multiversx_sdk/abi/list_value.py @@ -2,14 +2,19 @@ from typing import Any, Callable, Optional from multiversx_sdk.abi.interface import ISingleValue -from multiversx_sdk.abi.shared import (convert_native_value_to_list, - decode_length, encode_length) +from multiversx_sdk.abi.shared import ( + convert_native_value_to_list, + decode_length, + encode_length, +) class ListValue: - def __init__(self, - items: Optional[list[ISingleValue]] = None, - item_creator: Optional[Callable[[], ISingleValue]] = None) -> None: + def __init__( + self, + items: Optional[list[ISingleValue]] = None, + item_creator: Optional[Callable[[], ISingleValue]] = None, + ) -> None: self.items = items or [] self.item_creator = item_creator @@ -63,11 +68,7 @@ def get_payload(self) -> Any: return [item.get_payload() for item in self.items] def __eq__(self, other: Any) -> bool: - return ( - isinstance(other, ListValue) - and self.items == other.items - and self.item_creator == other.item_creator - ) + return isinstance(other, ListValue) and self.items == other.items and self.item_creator == other.item_creator def __iter__(self) -> Any: return iter(self.items) diff --git a/multiversx_sdk/abi/list_value_test.py b/multiversx_sdk/abi/list_value_test.py index 33748377..615d6f86 100644 --- a/multiversx_sdk/abi/list_value_test.py +++ b/multiversx_sdk/abi/list_value_test.py @@ -23,35 +23,34 @@ def test_set_payload_and_get_payload(): assert value.get_payload() == [4, 5, 6] # Nested (with recursion) - value = ListValue(item_creator=lambda: StructValue([ - Field("a", U32Value()), - Field("b", BigUIntValue()) - ])) + value = ListValue(item_creator=lambda: StructValue([Field("a", U32Value()), Field("b", BigUIntValue())])) - value.set_payload([ - {"a": 1, "b": 2}, - {"a": 3, "b": 4}, - {"a": 5, "b": 6} - ]) + value.set_payload([{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6}]) assert value.items == [ StructValue([Field("a", U32Value(1)), Field("b", BigUIntValue(2))]), StructValue([Field("a", U32Value(3)), Field("b", BigUIntValue(4))]), - StructValue([Field("a", U32Value(5)), Field("b", BigUIntValue(6))]) + StructValue([Field("a", U32Value(5)), Field("b", BigUIntValue(6))]), ] assert value.get_payload() == [ SimpleNamespace(a=1, b=2), SimpleNamespace(a=3, b=4), - SimpleNamespace(a=5, b=6) + SimpleNamespace(a=5, b=6), ] # With errors - with pytest.raises(ValueError, match="populating a list from a native object requires the item creator to be set"): + with pytest.raises( + ValueError, + match="populating a list from a native object requires the item creator to be set", + ): value = ListValue() value.set_payload([1, 2, 3]) # With errors - with pytest.raises(ValueError, match="cannot convert native value to list, because of: 'int' object is not iterable"): + with pytest.raises( + ValueError, + match="cannot convert native value to list, because of: 'int' object is not iterable", + ): value = ListValue(item_creator=lambda: U32Value()) value.set_payload(42) diff --git a/multiversx_sdk/abi/localnet_integration_test.py b/multiversx_sdk/abi/localnet_integration_test.py index 3db3feed..ef11e059 100644 --- a/multiversx_sdk/abi/localnet_integration_test.py +++ b/multiversx_sdk/abi/localnet_integration_test.py @@ -7,7 +7,9 @@ from multiversx_sdk.abi.managed_decimal_value import ManagedDecimalValue from multiversx_sdk.accounts.account import Account from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider -from multiversx_sdk.smart_contracts.smart_contract_controller import SmartContractController +from multiversx_sdk.smart_contracts.smart_contract_controller import ( + SmartContractController, +) from multiversx_sdk.testutils.wallets import load_wallets @@ -145,7 +147,10 @@ def test_managed_decimal(self): contract=contract, gas_limit=50_000_000, function="managed_decimal_addition_var", - arguments=[ManagedDecimalValue("4", 2, True), ManagedDecimalValue("5", 2, True)], + arguments=[ + ManagedDecimalValue("4", 2, True), + ManagedDecimalValue("5", 2, True), + ], ) tx_hash = proxy.send_transaction(addition_var_transaction) diff --git a/multiversx_sdk/abi/managed_decimal_signed_value.py b/multiversx_sdk/abi/managed_decimal_signed_value.py index 33d03494..fe9b9f4b 100644 --- a/multiversx_sdk/abi/managed_decimal_signed_value.py +++ b/multiversx_sdk/abi/managed_decimal_signed_value.py @@ -3,7 +3,10 @@ from typing import Any, Union from multiversx_sdk.abi.bigint_value import BigIntValue -from multiversx_sdk.abi.constants import U32_SIZE_IN_BYTES, LOCAL_CONTEXT_PRECISION_FOR_DECIMAL +from multiversx_sdk.abi.constants import ( + LOCAL_CONTEXT_PRECISION_FOR_DECIMAL, + U32_SIZE_IN_BYTES, +) from multiversx_sdk.abi.shared import read_bytes_exactly from multiversx_sdk.abi.small_int_values import U32Value diff --git a/multiversx_sdk/abi/managed_decimal_value.py b/multiversx_sdk/abi/managed_decimal_value.py index 81d877db..6157e645 100644 --- a/multiversx_sdk/abi/managed_decimal_value.py +++ b/multiversx_sdk/abi/managed_decimal_value.py @@ -3,7 +3,10 @@ from typing import Any, Union from multiversx_sdk.abi.biguint_value import BigUIntValue -from multiversx_sdk.abi.constants import U32_SIZE_IN_BYTES, LOCAL_CONTEXT_PRECISION_FOR_DECIMAL +from multiversx_sdk.abi.constants import ( + LOCAL_CONTEXT_PRECISION_FOR_DECIMAL, + U32_SIZE_IN_BYTES, +) from multiversx_sdk.abi.shared import read_bytes_exactly from multiversx_sdk.abi.small_int_values import U32Value diff --git a/multiversx_sdk/abi/multi_value_test.py b/multiversx_sdk/abi/multi_value_test.py index b79aa748..89a41038 100644 --- a/multiversx_sdk/abi/multi_value_test.py +++ b/multiversx_sdk/abi/multi_value_test.py @@ -7,10 +7,12 @@ def test_set_payload_and_get_payload(): # Simple - value = MultiValue([ - U32Value(), - StringValue(), - ]) + value = MultiValue( + [ + U32Value(), + StringValue(), + ] + ) value.set_payload([1, "hello"]) @@ -18,27 +20,34 @@ def test_set_payload_and_get_payload(): assert value.get_payload() == [1, "hello"] # Nested - value = MultiValue([ - StringValue(), - StringValue(), - MultiValue([ - U32Value(), + value = MultiValue( + [ + StringValue(), StringValue(), - ]) - ]) + MultiValue( + [ + U32Value(), + StringValue(), + ] + ), + ] + ) value.set_payload(["a", "b", [42, "hello"]]) assert value.items == [ StringValue("a"), StringValue("b"), - MultiValue([U32Value(42), StringValue("hello")]) + MultiValue([U32Value(42), StringValue("hello")]), ] assert value.get_payload() == ["a", "b", [42, "hello"]] # With errors - with pytest.raises(ValueError, match="cannot convert native value to list, because of: 'int' object is not iterable"): + with pytest.raises( + ValueError, + match="cannot convert native value to list, because of: 'int' object is not iterable", + ): value = MultiValue([U32Value(), StringValue()]) value.set_payload(42) diff --git a/multiversx_sdk/abi/option_value.py b/multiversx_sdk/abi/option_value.py index 357118ec..ef731b0b 100644 --- a/multiversx_sdk/abi/option_value.py +++ b/multiversx_sdk/abi/option_value.py @@ -1,8 +1,10 @@ import io from typing import Any, Optional -from multiversx_sdk.abi.constants import (OPTION_MARKER_FOR_ABSENT_VALUE, - OPTION_MARKER_FOR_PRESENT_VALUE) +from multiversx_sdk.abi.constants import ( + OPTION_MARKER_FOR_ABSENT_VALUE, + OPTION_MARKER_FOR_PRESENT_VALUE, +) from multiversx_sdk.abi.interface import ISingleValue from multiversx_sdk.abi.shared import read_bytes_exactly diff --git a/multiversx_sdk/abi/option_value_test.py b/multiversx_sdk/abi/option_value_test.py index a5ef68d9..4f355d67 100644 --- a/multiversx_sdk/abi/option_value_test.py +++ b/multiversx_sdk/abi/option_value_test.py @@ -21,14 +21,14 @@ def test_set_payload_and_get_payload(): assert value.get_payload() is None # Nested - value = OptionValue(StructValue([ - Field("a", U32Value()), - Field("b", BigUIntValue()) - ])) + value = OptionValue(StructValue([Field("a", U32Value()), Field("b", BigUIntValue())])) value.set_payload({"a": 41, "b": 42}) assert value.get_payload() == SimpleNamespace(a=41, b=42) # With errors - with pytest.raises(ValueError, match="placeholder value of option should be set before calling set_payload"): + with pytest.raises( + ValueError, + match="placeholder value of option should be set before calling set_payload", + ): OptionValue().set_payload(42) diff --git a/multiversx_sdk/abi/optional_value_test.py b/multiversx_sdk/abi/optional_value_test.py index f1881c08..f94eacd7 100644 --- a/multiversx_sdk/abi/optional_value_test.py +++ b/multiversx_sdk/abi/optional_value_test.py @@ -22,5 +22,8 @@ def test_set_payload_and_get_payload(): assert values.get_payload() == [42, "hello"] # With errors - with pytest.raises(ValueError, match="placeholder value of optional should be set before calling set_payload"): + with pytest.raises( + ValueError, + match="placeholder value of optional should be set before calling set_payload", + ): OptionalValue().set_payload(42) diff --git a/multiversx_sdk/abi/parts.py b/multiversx_sdk/abi/parts.py index dc49224b..d519b2a9 100644 --- a/multiversx_sdk/abi/parts.py +++ b/multiversx_sdk/abi/parts.py @@ -55,7 +55,9 @@ def focus_on_next_part(self): """ if self.is_focused_beyond_last_part(): - raise ValueError(f"cannot focus on next part, since the focus is already beyond the last part; focused part index is {self.focused_part_index}") + raise ValueError( + f"cannot focus on next part, since the focus is already beyond the last part; focused part index is {self.focused_part_index}" + ) self.focused_part_index += 1 def is_focused_beyond_last_part(self): diff --git a/multiversx_sdk/abi/serializer_test.py b/multiversx_sdk/abi/serializer_test.py index b58031cd..bff16d98 100644 --- a/multiversx_sdk/abi/serializer_test.py +++ b/multiversx_sdk/abi/serializer_test.py @@ -13,8 +13,7 @@ from multiversx_sdk.abi.option_value import OptionValue from multiversx_sdk.abi.optional_value import OptionalValue from multiversx_sdk.abi.serializer import Serializer -from multiversx_sdk.abi.small_int_values import (U8Value, U16Value, U32Value, - U64Value) +from multiversx_sdk.abi.small_int_values import U8Value, U16Value, U32Value, U64Value from multiversx_sdk.abi.string_value import StringValue from multiversx_sdk.abi.struct_value import StructValue from multiversx_sdk.abi.variadic_values import VariadicValues @@ -28,96 +27,120 @@ def test_serialize(): serializer = Serializer() # u8 - data = serializer.serialize([ - U8Value(0x42) - ]) + data = serializer.serialize([U8Value(0x42)]) assert data == "42" # u16 - data = serializer.serialize([ - U16Value(0x4243) - ]) + data = serializer.serialize([U16Value(0x4243)]) assert data == "4243" # u8, u16 - data = serializer.serialize([ - U8Value(0x42), - U16Value(0x4243), - ]) + data = serializer.serialize( + [ + U8Value(0x42), + U16Value(0x4243), + ] + ) assert data == "42@4243" # optional (missing) - data = serializer.serialize([ - U8Value(0x42), - OptionalValue(), - ]) + data = serializer.serialize( + [ + U8Value(0x42), + OptionalValue(), + ] + ) assert data == "42" # optional (provided) - data = serializer.serialize([ - U8Value(0x42), - OptionalValue(U8Value(0x43)), - ]) + data = serializer.serialize( + [ + U8Value(0x42), + OptionalValue(U8Value(0x43)), + ] + ) assert data == "42@43" # optional: should err because optional must be last with pytest.raises(ValueError, match="^an optional value must be last among input values$"): - serializer.serialize([ - OptionalValue(U8Value(0x43)), - U8Value(0x42), - ]) + serializer.serialize( + [ + OptionalValue(U8Value(0x43)), + U8Value(0x42), + ] + ) # multi - data = serializer.serialize([ - MultiValue([ - U8Value(0x42), - U16Value(0x4243), - U32Value(0x42434445), - ]), - ]) + data = serializer.serialize( + [ + MultiValue( + [ + U8Value(0x42), + U16Value(0x4243), + U32Value(0x42434445), + ] + ), + ] + ) assert data == "42@4243@42434445" # u8, multi - data = serializer.serialize([ - U8Value(0x42), - MultiValue([ + data = serializer.serialize( + [ U8Value(0x42), - U16Value(0x4243), - U32Value(0x42434445), - ]), - ]) + MultiValue( + [ + U8Value(0x42), + U16Value(0x4243), + U32Value(0x42434445), + ] + ), + ] + ) assert data == "42@42@4243@42434445" # multi, multi> - data = serializer.serialize([ - MultiValue([ - MultiValue([ - U8Value(0x42), - U16Value(0x4243), - ]), - MultiValue([ - U8Value(0x44), - U16Value(0x4445), - ]), - ]), - ]) + data = serializer.serialize( + [ + MultiValue( + [ + MultiValue( + [ + U8Value(0x42), + U16Value(0x4243), + ] + ), + MultiValue( + [ + U8Value(0x44), + U16Value(0x4445), + ] + ), + ] + ), + ] + ) assert data == "42@4243@44@4445" # variadic, of different types - data = serializer.serialize([ - VariadicValues([ - U8Value(0x42), - U16Value(0x4243), - ]), - ]) + data = serializer.serialize( + [ + VariadicValues( + [ + U8Value(0x42), + U16Value(0x4243), + ] + ), + ] + ) # For now, the serializer does not perform such a strict type check. # Although doable, it would be slightly complex and, if done, might be even dropped in the future @@ -126,44 +149,58 @@ def test_serialize(): # variadic, u8: should err because variadic must be last with pytest.raises(ValueError, match="^variadic values must be last among input values$"): - serializer.serialize([ - VariadicValues([ - U8Value(0x42), - U8Value(0x43), - ]), - U8Value(0x44), - ]) + serializer.serialize( + [ + VariadicValues( + [ + U8Value(0x42), + U8Value(0x43), + ] + ), + U8Value(0x44), + ] + ) # u8, variadic - data = serializer.serialize([ - U8Value(0x41), - VariadicValues([ - U8Value(0x42), - U8Value(0x43), - ]), - ]) + data = serializer.serialize( + [ + U8Value(0x41), + VariadicValues( + [ + U8Value(0x42), + U8Value(0x43), + ] + ), + ] + ) assert data == "41@42@43" # counted-variadic, of different types - data = serializer.serialize([ - CountedVariadicValues( - items=[ - U8Value(0x42), - U16Value(0x4243), - ]), - ]) + data = serializer.serialize( + [ + CountedVariadicValues( + items=[ + U8Value(0x42), + U16Value(0x4243), + ] + ), + ] + ) assert data == "02@42@4243" # variadic - data = serializer.serialize([ - CountedVariadicValues( - items=[ - U8Value(0x42), - U8Value(0x43), - ]), - U8Value(0x44), - ]) + data = serializer.serialize( + [ + CountedVariadicValues( + items=[ + U8Value(0x42), + U8Value(0x43), + ] + ), + U8Value(0x44), + ] + ) assert data == "02@42@43@44" @@ -255,57 +292,61 @@ def test_deserialize(): # multi output_values = [ - MultiValue([ - U8Value(), - U16Value(), - U32Value(), - ]), + MultiValue( + [ + U8Value(), + U16Value(), + U32Value(), + ] + ), ] serializer.deserialize("42@4243@42434445", output_values) assert output_values == [ - MultiValue([ - U8Value(0x42), - U16Value(0x4243), - U32Value(0x42434445), - ]), + MultiValue( + [ + U8Value(0x42), + U16Value(0x4243), + U32Value(0x42434445), + ] + ), ] # u8, multi output_values = [ U8Value(), - MultiValue([ - U8Value(), - U16Value(), - U32Value(), - ]), + MultiValue( + [ + U8Value(), + U16Value(), + U32Value(), + ] + ), ] serializer.deserialize("42@42@4243@42434445", output_values) assert output_values == [ U8Value(0x42), - MultiValue([ - U8Value(0x42), - U16Value(0x4243), - U32Value(0x42434445), - ]), + MultiValue( + [ + U8Value(0x42), + U16Value(0x4243), + U32Value(0x42434445), + ] + ), ] # empty: u8 - destination = VariadicValues( - item_creator=lambda: U8Value() - ) + destination = VariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("", [destination]) assert destination.items == [U8Value(0)] # variadic - destination = VariadicValues( - item_creator=lambda: U8Value() - ) + destination = VariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("2A@2B@2C", [destination]) @@ -316,9 +357,7 @@ def test_deserialize(): ] # variadic, with empty items - destination = VariadicValues( - item_creator=lambda: U8Value() - ) + destination = VariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("@01@00@", [destination]) @@ -330,9 +369,7 @@ def test_deserialize(): ] # variadic - destination = VariadicValues( - item_creator=lambda: U32Value() - ) + destination = VariadicValues(item_creator=lambda: U32Value()) serializer.deserialize("AABBCCDD@DDCCBBAA", [destination]) @@ -342,15 +379,19 @@ def test_deserialize(): ] # variadic, u8: should err because decoded value is too large - with pytest.raises(ValueError, match="^cannot decode \\(top-level\\) U8Value, because of: decoded value is too large or invalid \\(does not fit into 1 byte\\(s\\)\\): 256$"): - destination = VariadicValues( - item_creator=lambda: U8Value() - ) + with pytest.raises( + ValueError, + match="^cannot decode \\(top-level\\) U8Value, because of: decoded value is too large or invalid \\(does not fit into 1 byte\\(s\\)\\): 256$", + ): + destination = VariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("0100", [destination]) # # counted-variadic, variadic - destination = [CountedVariadicValues(item_creator=lambda: U32Value()), VariadicValues(item_creator=lambda: U32Value())] + destination = [ + CountedVariadicValues(item_creator=lambda: U32Value()), + VariadicValues(item_creator=lambda: U32Value()), + ] serializer.deserialize("03@41@42@43@44@45", destination) assert len(destination) == 2 @@ -364,15 +405,10 @@ def test_deserialize(): ] assert isinstance(destination[1], VariadicValues) - assert destination[1].items == [ - U32Value(0x44), - U32Value(0x45) - ] + assert destination[1].items == [U32Value(0x44), U32Value(0x45)] # counted-variadic - destination = CountedVariadicValues( - item_creator=lambda: U8Value() - ) + destination = CountedVariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("03@2A@2B@2C", [destination]) assert destination.length == 3 @@ -383,9 +419,7 @@ def test_deserialize(): ] # counted-variadic, with empty items - destination = CountedVariadicValues( - item_creator=lambda: U8Value() - ) + destination = CountedVariadicValues(item_creator=lambda: U8Value()) serializer.deserialize("04@@01@00@", [destination]) @@ -398,9 +432,7 @@ def test_deserialize(): ] # variadic - destination = CountedVariadicValues( - item_creator=lambda: U32Value() - ) + destination = CountedVariadicValues(item_creator=lambda: U32Value()) serializer.deserialize("02@AABBCCDD@DDCCBBAA", [destination]) @@ -419,11 +451,13 @@ def test_real_world_multisig_propose_batch(): serializer = Serializer() def create_esdt_token_payment(token_identifier: str, token_nonce: int, amount: int) -> StructValue: - return StructValue([ - Field("token_identifier", StringValue(token_identifier)), - Field("token_nonce", U64Value(token_nonce)), - Field("amount", BigUIntValue(amount)), - ]) + return StructValue( + [ + Field("token_identifier", StringValue(token_identifier)), + Field("token_nonce", U64Value(token_nonce)), + Field("amount", BigUIntValue(amount)), + ] + ) # First action: SendTransferExecuteEgld first_action = EnumValue( @@ -433,10 +467,15 @@ def create_esdt_token_payment(token_identifier: str, token_nonce: int, amount: i Field("egld_amount", BigUIntValue(one_quintillion)), Field("opt_gas_limit", OptionValue(U64Value(15_000_000))), Field("endpoint_name", BytesValue(b"example")), - Field("arguments", ListValue([ - BytesValue(bytes([0x03, 0x42])), - BytesValue(bytes([0x07, 0x43])), - ])), + Field( + "arguments", + ListValue( + [ + BytesValue(bytes([0x03, 0x42])), + BytesValue(bytes([0x07, 0x43])), + ] + ), + ), ], ) @@ -445,28 +484,42 @@ def create_esdt_token_payment(token_identifier: str, token_nonce: int, amount: i discriminant=6, fields=[ Field("to", AddressValue(alice_pub_key)), - Field("tokens", ListValue([ - create_esdt_token_payment("beer", 0, one_quintillion), - create_esdt_token_payment("chocolate", 0, one_quintillion), - ])), + Field( + "tokens", + ListValue( + [ + create_esdt_token_payment("beer", 0, one_quintillion), + create_esdt_token_payment("chocolate", 0, one_quintillion), + ] + ), + ), Field("opt_gas_limit", OptionValue(U64Value(15_000_000))), Field("endpoint_name", BytesValue(b"example")), - Field("arguments", ListValue([ - BytesValue(bytes([0x03, 0x42])), - BytesValue(bytes([0x07, 0x43])), - ])), + Field( + "arguments", + ListValue( + [ + BytesValue(bytes([0x03, 0x42])), + BytesValue(bytes([0x07, 0x43])), + ] + ), + ), ], ) - data = serializer.serialize([ - first_action, - second_action, - ]) + data = serializer.serialize( + [ + first_action, + second_action, + ] + ) - data_expected = "@".join([ - "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", - "06|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|00000002|0000000462656572|0000000000000000|000000080de0b6b3a7640000|0000000963686f636f6c617465|0000000000000000|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", - ]) + data_expected = "@".join( + [ + "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", + "06|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|00000002|0000000462656572|0000000000000000|000000080de0b6b3a7640000|0000000963686f636f6c617465|0000000000000000|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", + ] + ) # Drop the delimiters (were added for readability) data_expected = data_expected.replace("|", "") @@ -481,12 +534,14 @@ def test_real_world_multisig_get_pending_action_full_info(): serializer = Serializer() - data_hex = "".join([ - "0000002A", - "0000002A", - "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", - "00000002|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", - ]) + data_hex = "".join( + [ + "0000002A", + "0000002A", + "05|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|000000080de0b6b3a7640000|010000000000e4e1c0|000000076578616d706c65|00000002000000020342000000020743", + "00000002|0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1|8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", + ] + ) # Drop the delimiters (were added for readability) data = data_hex.replace("|", "") @@ -498,9 +553,7 @@ def test_real_world_multisig_get_pending_action_full_info(): action_egld_amount = BigUIntValue() action_gas_limit = U64Value() action_endpoint_name = BytesValue() - action_arguments = ListValue( - item_creator=lambda: BytesValue() - ) + action_arguments = ListValue(item_creator=lambda: BytesValue()) def action_fields_provider(discriminant: int) -> list[Field]: if discriminant == 5: @@ -514,21 +567,19 @@ def action_fields_provider(discriminant: int) -> list[Field]: return [] - action = EnumValue( - fields_provider=action_fields_provider - ) + action = EnumValue(fields_provider=action_fields_provider) - signers = ListValue( - item_creator=lambda: AddressValue() - ) + signers = ListValue(item_creator=lambda: AddressValue()) destination = VariadicValues( - item_creator=lambda: StructValue([ - Field("action_id", action_id), - Field("group_id", group_id), - Field("action_data", action), - Field("signers", signers), - ]), + item_creator=lambda: StructValue( + [ + Field("action_id", action_id), + Field("group_id", group_id), + Field("action_data", action), + Field("signers", signers), + ] + ), ) serializer.deserialize(data, [destination]) diff --git a/multiversx_sdk/abi/shared.py b/multiversx_sdk/abi/shared.py index 371e8f79..d3a7d3fe 100644 --- a/multiversx_sdk/abi/shared.py +++ b/multiversx_sdk/abi/shared.py @@ -18,7 +18,7 @@ def decode_length(reader: io.BytesIO) -> int: def read_bytes_exactly(reader: io.BytesIO, num_bytes: int): if num_bytes == 0: - return b'' + return b"" data = reader.read(num_bytes) if len(data) != num_bytes: @@ -39,7 +39,9 @@ def convert_native_value_to_dictionary(obj: Any, raise_on_failure: bool = True) error_on_dict_attribute = error if raise_on_failure: - raise ValueError(f"cannot convert native value to dictionary, because of: {error_on_dict_constructor} and {error_on_dict_attribute}") + raise ValueError( + f"cannot convert native value to dictionary, because of: {error_on_dict_constructor} and {error_on_dict_attribute}" + ) return {}, False diff --git a/multiversx_sdk/abi/shared_test.py b/multiversx_sdk/abi/shared_test.py index 975d83ab..a511832a 100644 --- a/multiversx_sdk/abi/shared_test.py +++ b/multiversx_sdk/abi/shared_test.py @@ -2,8 +2,10 @@ import pytest -from multiversx_sdk.abi.shared import (convert_native_value_to_dictionary, - convert_native_value_to_list) +from multiversx_sdk.abi.shared import ( + convert_native_value_to_dictionary, + convert_native_value_to_list, +) def test_convert_native_value_to_dictionary(): @@ -43,13 +45,7 @@ def test_convert_native_value_to_list(): # With errors (raise on failure) with pytest.raises(ValueError, match="cannot properly convert dictionary to list"): - items, ok = convert_native_value_to_list( - { - "a": 1, - "b": 2, - "c": 3 - } - ) + items, ok = convert_native_value_to_list({"a": 1, "b": 2, "c": 3}) with pytest.raises(ValueError, match="cannot convert native value to list"): items, ok = convert_native_value_to_list(42) diff --git a/multiversx_sdk/abi/small_int_values.py b/multiversx_sdk/abi/small_int_values.py index c33a2c12..5767bb5b 100644 --- a/multiversx_sdk/abi/small_int_values.py +++ b/multiversx_sdk/abi/small_int_values.py @@ -35,7 +35,9 @@ def decode_top_level(self, data: bytes): try: self.value.to_bytes(self._num_bytes, byteorder="big", signed=False) except OverflowError: - raise ValueError(f"decoded value is too large or invalid (does not fit into {self._num_bytes} byte(s)): {self.value}") + raise ValueError( + f"decoded value is too large or invalid (does not fit into {self._num_bytes} byte(s)): {self.value}" + ) def set_payload(self, value: Any): self.value = int(value) @@ -77,7 +79,9 @@ def decode_top_level(self, data: bytes): try: self.value.to_bytes(self._num_bytes, byteorder="big", signed=True) except OverflowError: - raise ValueError(f"decoded value is too large or invalid (does not fit into {self._num_bytes} byte(s)): {self.value}") + raise ValueError( + f"decoded value is too large or invalid (does not fit into {self._num_bytes} byte(s)): {self.value}" + ) def set_payload(self, value: Any): self.value = int(value) diff --git a/multiversx_sdk/abi/string_value.py b/multiversx_sdk/abi/string_value.py index 138b7587..beb28775 100644 --- a/multiversx_sdk/abi/string_value.py +++ b/multiversx_sdk/abi/string_value.py @@ -1,8 +1,7 @@ import io from typing import Any -from multiversx_sdk.abi.shared import (decode_length, encode_length, - read_bytes_exactly) +from multiversx_sdk.abi.shared import decode_length, encode_length, read_bytes_exactly class StringValue: @@ -32,7 +31,9 @@ def set_payload(self, value: Any): elif isinstance(value, StringValue): self.value = value.value else: - raise ValueError(f"cannot set payload for string (should be either a string or bytes, but got: {type(value)})") + raise ValueError( + f"cannot set payload for string (should be either a string or bytes, but got: {type(value)})" + ) def get_payload(self) -> Any: return self.value diff --git a/multiversx_sdk/abi/string_value_test.py b/multiversx_sdk/abi/string_value_test.py index ee5696d0..100711e9 100644 --- a/multiversx_sdk/abi/string_value_test.py +++ b/multiversx_sdk/abi/string_value_test.py @@ -23,5 +23,10 @@ def test_set_payload_and_get_payload(): assert value.get_payload() == "hello" # With errors - with pytest.raises(ValueError, match=re.escape("cannot set payload for string (should be either a string or bytes, but got: )")): + with pytest.raises( + ValueError, + match=re.escape( + "cannot set payload for string (should be either a string or bytes, but got: )" + ), + ): StringValue().set_payload(SimpleNamespace(a=1, b=2, c=3)) diff --git a/multiversx_sdk/abi/struct_value.py b/multiversx_sdk/abi/struct_value.py index 14b21d30..f540f677 100644 --- a/multiversx_sdk/abi/struct_value.py +++ b/multiversx_sdk/abi/struct_value.py @@ -2,12 +2,17 @@ from types import SimpleNamespace from typing import Any -from multiversx_sdk.abi.fields import (Field, decode_fields_nested, - encode_fields_nested, - set_fields_from_dictionary, - set_fields_from_list) -from multiversx_sdk.abi.shared import (convert_native_value_to_dictionary, - convert_native_value_to_list) +from multiversx_sdk.abi.fields import ( + Field, + decode_fields_nested, + encode_fields_nested, + set_fields_from_dictionary, + set_fields_from_list, +) +from multiversx_sdk.abi.shared import ( + convert_native_value_to_dictionary, + convert_native_value_to_list, +) class StructValue: diff --git a/multiversx_sdk/abi/struct_value_test.py b/multiversx_sdk/abi/struct_value_test.py index 460c35bc..532c0636 100644 --- a/multiversx_sdk/abi/struct_value_test.py +++ b/multiversx_sdk/abi/struct_value_test.py @@ -11,13 +11,13 @@ def test_set_payload_and_get_payload(): # With errors - with pytest.raises(ValueError, match=re.escape("cannot set payload for struct (should be either a dictionary or a list)")): + with pytest.raises( + ValueError, + match=re.escape("cannot set payload for struct (should be either a dictionary or a list)"), + ): StructValue([]).set_payload(42) - value = StructValue([ - Field("a", U32Value()), - Field("b", BigUIntValue()) - ]) + value = StructValue([Field("a", U32Value()), Field("b", BigUIntValue())]) # From list value.set_payload([39, 40]) diff --git a/multiversx_sdk/abi/tuple_value.py b/multiversx_sdk/abi/tuple_value.py index 9d3effda..b659e472 100644 --- a/multiversx_sdk/abi/tuple_value.py +++ b/multiversx_sdk/abi/tuple_value.py @@ -34,7 +34,9 @@ def set_payload(self, value: Any): native_list, ok = convert_native_value_to_list(value, raise_on_failure=False) if ok: if len(self.fields) != len(native_list): - raise ValueError(f"the number of fields ({len(self.fields)}) does not match the number of provided native values ({len(native_list)})") + raise ValueError( + f"the number of fields ({len(self.fields)}) does not match the number of provided native values ({len(native_list)})" + ) for i, field in enumerate(self.fields): field.set_payload(native_list[i]) diff --git a/multiversx_sdk/abi/tuple_value_test.py b/multiversx_sdk/abi/tuple_value_test.py index edd762d7..54bbe76a 100644 --- a/multiversx_sdk/abi/tuple_value_test.py +++ b/multiversx_sdk/abi/tuple_value_test.py @@ -9,13 +9,18 @@ def test_set_payload_and_get_payload(): # With errors - with pytest.raises(ValueError, match=re.escape("cannot set payload for tuple (should be either a tuple or a list)")): + with pytest.raises( + ValueError, + match=re.escape("cannot set payload for tuple (should be either a tuple or a list)"), + ): TupleValue([]).set_payload(42) - value = TupleValue([ - U32Value(), - StringValue(), - ]) + value = TupleValue( + [ + U32Value(), + StringValue(), + ] + ) # From tuple value.set_payload((41, "hello")) diff --git a/multiversx_sdk/abi/type_formula.py b/multiversx_sdk/abi/type_formula.py index 4aa415f9..69b0dee6 100644 --- a/multiversx_sdk/abi/type_formula.py +++ b/multiversx_sdk/abi/type_formula.py @@ -1,5 +1,5 @@ class TypeFormula: - def __init__(self, name: str, type_parameters: list['TypeFormula']) -> None: + def __init__(self, name: str, type_parameters: list["TypeFormula"]) -> None: self.name: str = name self.type_parameters: list[TypeFormula] = type_parameters diff --git a/multiversx_sdk/abi/type_formula_parser.py b/multiversx_sdk/abi/type_formula_parser.py index dc937d2e..1faf3d9a 100644 --- a/multiversx_sdk/abi/type_formula_parser.py +++ b/multiversx_sdk/abi/type_formula_parser.py @@ -1,4 +1,3 @@ - from typing import Any from multiversx_sdk.abi.type_formula import TypeFormula diff --git a/multiversx_sdk/abi/type_formula_parser_test.py b/multiversx_sdk/abi/type_formula_parser_test.py index bbdb7a2d..90af4f51 100644 --- a/multiversx_sdk/abi/type_formula_parser_test.py +++ b/multiversx_sdk/abi/type_formula_parser_test.py @@ -8,11 +8,14 @@ def test_parse_expression(): ("i64", "i64"), (" i64 ", "i64"), ("utf-8 string", "utf-8 string"), - ("MultiResultVec>", "MultiResultVec>"), + ( + "MultiResultVec>", + "MultiResultVec>", + ), ("tuple3>", "tuple3>"), ("tuple2", "tuple2"), ("tuple2 ", "tuple2"), - ("tuple, List>", "tuple, List>") + ("tuple, List>", "tuple, List>"), ] for input_expression, expected_expression in test_vectors: diff --git a/multiversx_sdk/abi/typesystem_test.py b/multiversx_sdk/abi/typesystem_test.py index e2d80bc6..929be8b0 100644 --- a/multiversx_sdk/abi/typesystem_test.py +++ b/multiversx_sdk/abi/typesystem_test.py @@ -2,10 +2,14 @@ from multiversx_sdk.abi.multi_value import MultiValue from multiversx_sdk.abi.optional_value import OptionalValue from multiversx_sdk.abi.small_int_values import U32Value, U64Value -from multiversx_sdk.abi.typesystem import (is_bytes, is_list_of_bytes, - is_list_of_typed_values, - is_multi_value, is_single_value, - is_typed_value) +from multiversx_sdk.abi.typesystem import ( + is_bytes, + is_list_of_bytes, + is_list_of_typed_values, + is_multi_value, + is_single_value, + is_typed_value, +) from multiversx_sdk.abi.variadic_values import VariadicValues diff --git a/multiversx_sdk/abi/variadic_values.py b/multiversx_sdk/abi/variadic_values.py index d990cd0f..327953f8 100644 --- a/multiversx_sdk/abi/variadic_values.py +++ b/multiversx_sdk/abi/variadic_values.py @@ -6,9 +6,11 @@ class VariadicValues(IPayloadHolder): - def __init__(self, - items: Optional[list[Union[ISingleValue, MultiValue]]] = None, - item_creator: Optional[Callable[[], Union[ISingleValue, MultiValue]]] = None) -> None: + def __init__( + self, + items: Optional[list[Union[ISingleValue, MultiValue]]] = None, + item_creator: Optional[Callable[[], Union[ISingleValue, MultiValue]]] = None, + ) -> None: self.items = items or [] self.item_creator = item_creator @@ -30,9 +32,7 @@ def get_payload(self) -> Any: def __eq__(self, other: Any) -> bool: return ( - isinstance(other, VariadicValues) - and self.items == other.items - and self.item_creator == other.item_creator + isinstance(other, VariadicValues) and self.items == other.items and self.item_creator == other.item_creator ) def __iter__(self) -> Any: diff --git a/multiversx_sdk/abi/variadic_values_test.py b/multiversx_sdk/abi/variadic_values_test.py index 76d1f319..7467ca32 100644 --- a/multiversx_sdk/abi/variadic_values_test.py +++ b/multiversx_sdk/abi/variadic_values_test.py @@ -22,13 +22,16 @@ def test_set_payload_and_get_payload(): assert values.items == [ MultiValue([U32Value(42), StringValue("hello")]), - MultiValue([U32Value(43), StringValue("world")]) + MultiValue([U32Value(43), StringValue("world")]), ] assert values.get_payload() == [[42, "hello"], [43, "world"]] # With errors - with pytest.raises(ValueError, match="populating variadic values from a native object requires the item creator to be set"): + with pytest.raises( + ValueError, + match="populating variadic values from a native object requires the item creator to be set", + ): VariadicValues().set_payload([1, 2, 3]) # With errors diff --git a/multiversx_sdk/account_management/__init__.py b/multiversx_sdk/account_management/__init__.py index 4bf9120d..586f86ea 100644 --- a/multiversx_sdk/account_management/__init__.py +++ b/multiversx_sdk/account_management/__init__.py @@ -1,6 +1,6 @@ -from multiversx_sdk.account_management.account_controller import \ - AccountController -from multiversx_sdk.account_management.account_transactions_factory import \ - AccountTransactionsFactory +from multiversx_sdk.account_management.account_controller import AccountController +from multiversx_sdk.account_management.account_transactions_factory import ( + AccountTransactionsFactory, +) __all__ = ["AccountTransactionsFactory", "AccountController"] diff --git a/multiversx_sdk/account_management/account_controller.py b/multiversx_sdk/account_management/account_controller.py index 65d509ec..092436ea 100644 --- a/multiversx_sdk/account_management/account_controller.py +++ b/multiversx_sdk/account_management/account_controller.py @@ -43,7 +43,9 @@ def create_transaction_for_setting_guardian( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_setting_guardian( - sender=sender.address, guardian_address=guardian_address, service_id=service_id + sender=sender.address, + guardian_address=guardian_address, + service_id=service_id, ) transaction.relayer = relayer @@ -68,7 +70,11 @@ def create_transaction_for_guarding_account( return transaction def create_transaction_for_unguarding_account( - self, sender: IAccount, nonce: int, guardian: Address, relayer: Optional[Address] = None + self, + sender: IAccount, + nonce: int, + guardian: Address, + relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_unguarding_account(sender=sender.address, guardian=guardian) diff --git a/multiversx_sdk/account_management/account_transactions_factory.py b/multiversx_sdk/account_management/account_transactions_factory.py index be578edc..a619b166 100644 --- a/multiversx_sdk/account_management/account_transactions_factory.py +++ b/multiversx_sdk/account_management/account_transactions_factory.py @@ -1,17 +1,16 @@ from multiversx_sdk.builders.transaction_builder import TransactionBuilder from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction import Transaction -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig class AccountTransactionsFactory: def __init__(self, config: TransactionsFactoryConfig) -> None: self.config = config - def create_transaction_for_saving_key_value(self, - sender: Address, - key_value_pairs: dict[bytes, bytes]) -> Transaction: + def create_transaction_for_saving_key_value( + self, sender: Address, key_value_pairs: dict[bytes, bytes] + ) -> Transaction: function = "SaveKeyValue" extra_gas = self._compute_extra_gas_for_saving_key_value(key_value_pairs) @@ -25,17 +24,16 @@ def create_transaction_for_saving_key_value(self, receiver=sender, data_parts=data_parts, gas_limit=extra_gas, - add_data_movement_gas=True + add_data_movement_gas=True, ).build() - def create_transaction_for_setting_guardian(self, - sender: Address, - guardian_address: Address, - service_id: str) -> Transaction: + def create_transaction_for_setting_guardian( + self, sender: Address, guardian_address: Address, service_id: str + ) -> Transaction: data_parts = [ "SetGuardian", guardian_address.to_hex(), - service_id.encode().hex() + service_id.encode().hex(), ] return TransactionBuilder( @@ -44,7 +42,7 @@ def create_transaction_for_setting_guardian(self, receiver=sender, data_parts=data_parts, gas_limit=self.config.gas_limit_set_guardian, - add_data_movement_gas=True + add_data_movement_gas=True, ).build() def create_transaction_for_guarding_account(self, sender: Address) -> Transaction: @@ -56,7 +54,7 @@ def create_transaction_for_guarding_account(self, sender: Address) -> Transactio receiver=sender, data_parts=data_parts, gas_limit=self.config.gas_limit_guard_account, - add_data_movement_gas=True + add_data_movement_gas=True, ).build() def create_transaction_for_unguarding_account(self, sender: Address, guardian: Address) -> Transaction: @@ -68,7 +66,7 @@ def create_transaction_for_unguarding_account(self, sender: Address, guardian: A receiver=sender, data_parts=data_parts, gas_limit=self.config.gas_limit_unguard_account, - add_data_movement_gas=True + add_data_movement_gas=True, ).build() transaction.options = 2 transaction.guardian = guardian @@ -87,7 +85,8 @@ def _compute_extra_gas_for_saving_key_value(self, key_value_pairs: dict[bytes, b extra_gas = 0 for key, value in key_value_pairs.items(): - extra_gas += self.config.gas_limit_persist_per_byte * (len(key) + len(value)) + \ - self.config.gas_limit_store_per_byte * len(value) + extra_gas += self.config.gas_limit_persist_per_byte * ( + len(key) + len(value) + ) + self.config.gas_limit_store_per_byte * len(value) return extra_gas + self.config.gas_limit_save_key_value diff --git a/multiversx_sdk/account_management/account_transactions_factory_test.py b/multiversx_sdk/account_management/account_transactions_factory_test.py index 23e185db..4a3ad802 100644 --- a/multiversx_sdk/account_management/account_transactions_factory_test.py +++ b/multiversx_sdk/account_management/account_transactions_factory_test.py @@ -1,8 +1,8 @@ -from multiversx_sdk.account_management.account_controller import \ - AccountTransactionsFactory +from multiversx_sdk.account_management.account_controller import ( + AccountTransactionsFactory, +) from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig class TestAccountTransactionsFactory: @@ -16,10 +16,7 @@ def test_save_key_value(self): value = "value0".encode() pairs[key] = value - tx = self.factory.create_transaction_for_saving_key_value( - sender=sender, - key_value_pairs=pairs - ) + tx = self.factory.create_transaction_for_saving_key_value(sender=sender, key_value_pairs=pairs) assert tx.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert tx.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -32,14 +29,15 @@ def test_set_guardian(self): service_id = "MultiversXTCSService" tx = self.factory.create_transaction_for_setting_guardian( - sender=sender, - guardian_address=guardian, - service_id=service_id + sender=sender, guardian_address=guardian, service_id=service_id ) assert tx.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert tx.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert tx.data.decode() == "SetGuardian@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@4d756c7469766572735854435353657276696365" + assert ( + tx.data.decode() + == "SetGuardian@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@4d756c7469766572735854435353657276696365" + ) assert tx.gas_limit == 475500 def test_guard_account(self): diff --git a/multiversx_sdk/accounts/account_test.py b/multiversx_sdk/accounts/account_test.py index 059bbaad..00eef9ae 100644 --- a/multiversx_sdk/accounts/account_test.py +++ b/multiversx_sdk/accounts/account_test.py @@ -1,4 +1,3 @@ - from pathlib import Path from multiversx_sdk.accounts.account import Account @@ -16,30 +15,26 @@ def test_create_account_from_pem(): account = Account.new_from_pem(alice) - assert account.secret_key.get_bytes().hex( - ) == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" + assert account.secret_key.get_bytes().hex() == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" assert account.address.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" def test_create_account_from_keystore(): account = Account.new_from_keystore(testwallets / "withDummyMnemonic.json", "password") - assert account.secret_key.get_bytes().hex( - ) == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" + assert account.secret_key.get_bytes().hex() == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" assert account.address.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" def test_create_account_from_mnemonic(): account = Account.new_from_mnemonic(DUMMY_MNEMONIC) - assert account.secret_key.get_bytes().hex( - ) == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" + assert account.secret_key.get_bytes().hex() == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" assert account.address.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" def test_create_account_from_keypair(): - secret_key = UserSecretKey.new_from_string( - "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9") + secret_key = UserSecretKey.new_from_string("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9") keypair = KeyPair(secret_key) account = Account.new_from_keypair(keypair) @@ -67,27 +62,33 @@ def test_sign_transaction(): tx = Transaction( nonce=89, value=0, - receiver=Address.new_from_bech32( - "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"), - sender=Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + receiver=Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"), + sender=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), data=None, gas_price=1000000000, gas_limit=50000, chain_id="local-testnet", version=1, - options=0 + options=0, ) account = Account.new_from_pem(alice) tx.signature = account.sign_transaction(tx) - assert tx.signature.hex() == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + assert ( + tx.signature.hex() + == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + ) def test_sign_message(): - message = Message("hello".encode(), address=Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")) + message = Message( + "hello".encode(), + address=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + ) account = Account.new_from_pem(alice) message.signature = account.sign_message(message) - assert message.signature.hex() == "561bc58f1dc6b10de208b2d2c22c9a474ea5e8cabb59c3d3ce06bbda21cc46454aa71a85d5a60442bd7784effa2e062fcb8fb421c521f898abf7f5ec165e5d0f" + assert ( + message.signature.hex() + == "561bc58f1dc6b10de208b2d2c22c9a474ea5e8cabb59c3d3ce06bbda21cc46454aa71a85d5a60442bd7784effa2e062fcb8fb421c521f898abf7f5ec165e5d0f" + ) diff --git a/multiversx_sdk/builders/token_transfers_data_builder.py b/multiversx_sdk/builders/token_transfers_data_builder.py index b27bbbfc..9fabd41e 100644 --- a/multiversx_sdk/builders/token_transfers_data_builder.py +++ b/multiversx_sdk/builders/token_transfers_data_builder.py @@ -16,10 +16,9 @@ def __init__(self, token_computer: TokenComputer) -> None: def build_args_for_esdt_transfer(self, transfer: TokenTransfer) -> list[str]: args = ["ESDTTransfer"] - serialized_args = self.serializer.serialize_to_parts([ - StringValue(transfer.token.identifier), - BigUIntValue(transfer.amount) - ]) + serialized_args = self.serializer.serialize_to_parts( + [StringValue(transfer.token.identifier), BigUIntValue(transfer.amount)] + ) args.extend([arg.hex() for arg in serialized_args]) return args @@ -29,11 +28,13 @@ def build_args_for_single_esdt_nft_transfer(self, transfer: TokenTransfer, recei token = transfer.token identifier = self.token_computer.extract_identifier_from_extended_identifier(token.identifier) - serialized_args = self.serializer.serialize_to_parts([ - StringValue(identifier), - BigUIntValue(token.nonce), - BigUIntValue(transfer.amount) - ]) + serialized_args = self.serializer.serialize_to_parts( + [ + StringValue(identifier), + BigUIntValue(token.nonce), + BigUIntValue(transfer.amount), + ] + ) args.extend([arg.hex() for arg in serialized_args]) args.append(receiver.to_hex()) @@ -45,11 +46,13 @@ def build_args_for_multi_esdt_nft_transfer(self, receiver: Address, transfers: l for transfer in transfers: identifier = self.token_computer.extract_identifier_from_extended_identifier(transfer.token.identifier) - serialized_args = self.serializer.serialize_to_parts([ - StringValue(identifier), - BigUIntValue(transfer.token.nonce), - BigUIntValue(transfer.amount) - ]) + serialized_args = self.serializer.serialize_to_parts( + [ + StringValue(identifier), + BigUIntValue(transfer.token.nonce), + BigUIntValue(transfer.amount), + ] + ) args.extend([arg.hex() for arg in serialized_args]) return args diff --git a/multiversx_sdk/builders/transaction_builder.py b/multiversx_sdk/builders/transaction_builder.py index cc554b62..df7fb524 100644 --- a/multiversx_sdk/builders/transaction_builder.py +++ b/multiversx_sdk/builders/transaction_builder.py @@ -2,8 +2,7 @@ from multiversx_sdk.core import Address, Transaction from multiversx_sdk.core.constants import ARGS_SEPARATOR -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig class TransactionBuilder: @@ -12,14 +11,16 @@ class TransactionBuilder: Used for the transactions factories. """ - def __init__(self, - config: TransactionsFactoryConfig, - sender: Address, - receiver: Address, - data_parts: list[str], - gas_limit: int, - add_data_movement_gas: bool, - amount: Optional[int] = None) -> None: + def __init__( + self, + config: TransactionsFactoryConfig, + sender: Address, + receiver: Address, + data_parts: list[str], + gas_limit: int, + add_data_movement_gas: bool, + amount: Optional[int] = None, + ) -> None: self.config = config self.sender = sender self.receiver = receiver @@ -51,7 +52,7 @@ def build(self) -> Transaction: gas_limit=gas_limit, chain_id=self.config.chain_id, data=data, - value=self.amount + value=self.amount, ) return transaction diff --git a/multiversx_sdk/core/__init__.py b/multiversx_sdk/core/__init__.py index 3d853923..3dda53e3 100644 --- a/multiversx_sdk/core/__init__.py +++ b/multiversx_sdk/core/__init__.py @@ -1,28 +1,48 @@ -from multiversx_sdk.core.address import (Address, AddressComputer, - AddressFactory) +from multiversx_sdk.core.address import Address, AddressComputer, AddressFactory from multiversx_sdk.core.code_metadata import CodeMetadata from multiversx_sdk.core.config import LibraryConfig from multiversx_sdk.core.message import Message, MessageComputer -from multiversx_sdk.core.tokens import (Token, TokenComputer, - TokenIdentifierParts, TokenTransfer) +from multiversx_sdk.core.tokens import ( + Token, + TokenComputer, + TokenIdentifierParts, + TokenTransfer, +) from multiversx_sdk.core.transaction import Transaction from multiversx_sdk.core.transaction_computer import TransactionComputer -from multiversx_sdk.core.transaction_events_parser import \ - TransactionEventsParser +from multiversx_sdk.core.transaction_events_parser import TransactionEventsParser from multiversx_sdk.core.transaction_on_network import ( - SmartContractResult, TransactionEvent, TransactionLogs, - TransactionOnNetwork, TransactionStatus, find_events_by_first_topic, - find_events_by_identifier) -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig + SmartContractResult, + TransactionEvent, + TransactionLogs, + TransactionOnNetwork, + TransactionStatus, + find_events_by_first_topic, + find_events_by_identifier, +) +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig __all__ = [ - "Address", "AddressFactory", "AddressComputer", - "Transaction", "TransactionComputer", - "Message", "MessageComputer", "CodeMetadata", - "Token", "TokenComputer", "TokenTransfer", "TokenIdentifierParts", - "SmartContractResult", "TransactionEvent", "TransactionLogs", - "TransactionOnNetwork", "TransactionStatus", "TransactionsFactoryConfig", - "find_events_by_identifier", "find_events_by_first_topic", "TransactionEventsParser", - "LibraryConfig" + "Address", + "AddressFactory", + "AddressComputer", + "Transaction", + "TransactionComputer", + "Message", + "MessageComputer", + "CodeMetadata", + "Token", + "TokenComputer", + "TokenTransfer", + "TokenIdentifierParts", + "SmartContractResult", + "TransactionEvent", + "TransactionLogs", + "TransactionOnNetwork", + "TransactionStatus", + "TransactionsFactoryConfig", + "find_events_by_identifier", + "find_events_by_first_topic", + "TransactionEventsParser", + "LibraryConfig", ] diff --git a/multiversx_sdk/core/address.py b/multiversx_sdk/core/address.py index f11fe46a..3c745508 100644 --- a/multiversx_sdk/core/address.py +++ b/multiversx_sdk/core/address.py @@ -173,9 +173,7 @@ def compute_contract_address(self, deployer: Address, deployment_nonce: int) -> nonce_bytes = deployment_nonce.to_bytes(8, byteorder="little") bytes_to_hash = deployer_pubkey + nonce_bytes contract_pubkey = keccak.new(digest_bits=256).update(bytes_to_hash).digest() - contract_pubkey = ( - bytes([0] * 8) + bytes([5, 0]) + contract_pubkey[10:30] + deployer_pubkey[30:] - ) + contract_pubkey = bytes([0] * 8) + bytes([5, 0]) + contract_pubkey[10:30] + deployer_pubkey[30:] return Address(contract_pubkey, deployer.get_hrp()) def get_shard_of_address(self, address: Address) -> int: @@ -223,9 +221,7 @@ def get_shard_of_pubkey(pubkey: bytes, number_of_shards: int) -> int: def _is_pubkey_of_metachain(pubkey: bytes) -> bool: - metachain_prefix = bytearray( - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - ) + metachain_prefix = bytearray([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) pubkey_prefix = pubkey[0 : len(metachain_prefix)] if pubkey_prefix == bytes(metachain_prefix): return True diff --git a/multiversx_sdk/core/address_test.py b/multiversx_sdk/core/address_test.py index d3589bcb..cdefcfa0 100644 --- a/multiversx_sdk/core/address_test.py +++ b/multiversx_sdk/core/address_test.py @@ -1,8 +1,11 @@ - import pytest -from multiversx_sdk.core.address import (Address, AddressComputer, - AddressFactory, is_valid_bech32) +from multiversx_sdk.core.address import ( + Address, + AddressComputer, + AddressFactory, + is_valid_bech32, +) from multiversx_sdk.core.config import LibraryConfig from multiversx_sdk.core.errors import BadAddressError, BadPubkeyLengthError @@ -11,7 +14,10 @@ def test_address(): address = Address.new_from_bech32("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz") assert str(address) == "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" assert address == Address.new_from_bech32("erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz") - assert not address == Address(bytes.fromhex("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"), "test") + assert not address == Address( + bytes.fromhex("fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293"), + "test", + ) assert "fd691bb5e85d102687d81079dffce842d4dc328276d2d4c60d8fd1c3433c3293" == address.to_hex() assert "erd1l453hd0gt5gzdp7czpuall8ggt2dcv5zwmfdf3sd3lguxseux2fsmsgldz" == address.to_bech32() @@ -45,8 +51,14 @@ def test_address_factory(): factory_erd = AddressFactory("erd") pubkey = bytes.fromhex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1") - assert factory_foo.create_from_public_key(pubkey).to_bech32() == "foo1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssunhpj4" - assert factory_erd.create_from_public_key(pubkey).to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert ( + factory_foo.create_from_public_key(pubkey).to_bech32() + == "foo1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssunhpj4" + ) + assert ( + factory_erd.create_from_public_key(pubkey).to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) def test_is_valid_bech32(): diff --git a/multiversx_sdk/core/bech32.py b/multiversx_sdk/core/bech32.py index 05149218..b1f38d1b 100644 --- a/multiversx_sdk/core/bech32.py +++ b/multiversx_sdk/core/bech32.py @@ -28,11 +28,11 @@ def bech32_polymod(values: List[int]): """Internal function that computes the Bech32 checksum.""" - generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] + generator = [0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3] chk = 1 for value in values: top = chk >> 25 - chk = (chk & 0x1ffffff) << 5 ^ value + chk = (chk & 0x1FFFFFF) << 5 ^ value for i in range(5): chk ^= generator[i] if ((top >> i) & 1) else 0 return chk @@ -58,21 +58,21 @@ def bech32_create_checksum(hrp: str, data: List[int]): def bech32_encode(hrp: str, data: List[int]): """Compute a Bech32 string given HRP and data values.""" combined = data + bech32_create_checksum(hrp, data) - return hrp + '1' + ''.join([CHARSET[d] for d in combined]) + return hrp + "1" + "".join([CHARSET[d] for d in combined]) def bech32_decode(bech: str): """Validate a Bech32 string, and determine HRP and data.""" - if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (bech.lower() != bech and bech.upper() != bech)): + if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (bech.lower() != bech and bech.upper() != bech): return (None, None) bech = bech.lower() - pos = bech.rfind('1') + pos = bech.rfind("1") if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: return (None, None) - if not all(x in CHARSET for x in bech[pos + 1:]): + if not all(x in CHARSET for x in bech[pos + 1 :]): return (None, None) hrp = bech[:pos] - data = [CHARSET.find(x) for x in bech[pos + 1:]] + data = [CHARSET.find(x) for x in bech[pos + 1 :]] if not bech32_verify_checksum(hrp, data): return (None, None) return (hrp, data[:-6]) diff --git a/multiversx_sdk/core/code_metadata.py b/multiversx_sdk/core/code_metadata.py index dc5f1ac7..8b7d9416 100644 --- a/multiversx_sdk/core/code_metadata.py +++ b/multiversx_sdk/core/code_metadata.py @@ -16,7 +16,13 @@ class ByteOne(Enum): class CodeMetadata: - def __init__(self, upgradeable: bool = True, readable: bool = True, payable: bool = False, payable_by_contract: bool = False): + def __init__( + self, + upgradeable: bool = True, + readable: bool = True, + payable: bool = False, + payable_by_contract: bool = False, + ): self.upgradeable = upgradeable self.readable = readable self.payable = payable diff --git a/multiversx_sdk/core/code_metadata_test.py b/multiversx_sdk/core/code_metadata_test.py index bd7066f0..daebc908 100644 --- a/multiversx_sdk/core/code_metadata_test.py +++ b/multiversx_sdk/core/code_metadata_test.py @@ -1,5 +1,3 @@ - - import pytest from multiversx_sdk.core.code_metadata import CodeMetadata @@ -37,6 +35,12 @@ def test_code_metadata_new_from_bytes(): def test_code_metadata_serialize(): assert CodeMetadata().serialize() == bytes([0x05, 0x00]) assert CodeMetadata(upgradeable=True, readable=True).serialize() == bytes([0x05, 0x00]) - assert CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True).serialize() == bytes([0x05, 0x06]) - assert CodeMetadata(upgradeable=True, readable=True, payable=False, payable_by_contract=True).serialize() == bytes([0x05, 0x04]) - assert CodeMetadata(upgradeable=False, readable=False, payable=False, payable_by_contract=False).serialize() == bytes([0x00, 0x00]) + assert CodeMetadata(upgradeable=True, readable=True, payable=True, payable_by_contract=True).serialize() == bytes( + [0x05, 0x06] + ) + assert CodeMetadata(upgradeable=True, readable=True, payable=False, payable_by_contract=True).serialize() == bytes( + [0x05, 0x04] + ) + assert CodeMetadata( + upgradeable=False, readable=False, payable=False, payable_by_contract=False + ).serialize() == bytes([0x00, 0x00]) diff --git a/multiversx_sdk/core/message.py b/multiversx_sdk/core/message.py index 24384380..9edb0d14 100644 --- a/multiversx_sdk/core/message.py +++ b/multiversx_sdk/core/message.py @@ -3,17 +3,22 @@ from Cryptodome.Hash import keccak from multiversx_sdk.core.address import Address -from multiversx_sdk.core.constants import (DEFAULT_MESSAGE_VERSION, - SDK_PY_SIGNER, UNKNOWN_SIGNER) +from multiversx_sdk.core.constants import ( + DEFAULT_MESSAGE_VERSION, + SDK_PY_SIGNER, + UNKNOWN_SIGNER, +) class Message: - def __init__(self, - data: bytes, - signature: bytes = b"", - address: Optional[Address] = None, - version: int = DEFAULT_MESSAGE_VERSION, - signer: str = SDK_PY_SIGNER) -> None: + def __init__( + self, + data: bytes, + signature: bytes = b"", + address: Optional[Address] = None, + version: int = DEFAULT_MESSAGE_VERSION, + signer: str = SDK_PY_SIGNER, + ) -> None: self.data = data self.signature = signature self.address = address @@ -48,7 +53,7 @@ def pack_message(self, message: Message) -> Dict[str, Any]: "message": message.data.hex(), "signature": message.signature.hex(), "version": message.version, - "signer": message.signer + "signer": message.signer, } def unpack_message(self, packed_message: Dict[str, Any]) -> Message: @@ -69,7 +74,7 @@ def unpack_message(self, packed_message: Dict[str, Any]) -> Message: address=address, signature=bytes.fromhex(signature), version=version, - signer=signer + signer=signer, ) def _trim_hex_prefix(self, data: str) -> str: diff --git a/multiversx_sdk/core/message_test.py b/multiversx_sdk/core/message_test.py index b67fd1ff..d1d56b82 100644 --- a/multiversx_sdk/core/message_test.py +++ b/multiversx_sdk/core/message_test.py @@ -12,22 +12,20 @@ def test_message_v1_serialize_for_signing(): - message = Message( - data="test message".encode() - ) + message = Message(data="test message".encode()) serialized = message_computer.compute_bytes_for_signing(message) assert serialized.hex() == "2162d6271208429e6d3e664139e98ba7c5f1870906fb113e8903b1d3f531004d" def test_sign_packed_message_and_verify_unpacked_message(): - message = Message( - data="test".encode(), - address=alice - ) + message = Message(data="test".encode(), address=alice) signer = UserSigner.from_pem_file(parent / "testutils" / "testwallets" / "alice.pem") message.signature = signer.sign(message_computer.compute_bytes_for_signing(message)) - assert message.signature.hex() == "7aff43cd6e3d880a65033bf0a1b16274854fd7dfa9fe5faa7fa9a665ee851afd4c449310f5f1697d348e42d1819eaef69080e33e7652d7393521ed50d7427a0e" + assert ( + message.signature.hex() + == "7aff43cd6e3d880a65033bf0a1b16274854fd7dfa9fe5faa7fa9a665ee851afd4c449310f5f1697d348e42d1819eaef69080e33e7652d7393521ed50d7427a0e" + ) packed_message = message_computer.pack_message(message) assert packed_message == { @@ -35,7 +33,7 @@ def test_sign_packed_message_and_verify_unpacked_message(): "message": "74657374", "signature": "7aff43cd6e3d880a65033bf0a1b16274854fd7dfa9fe5faa7fa9a665ee851afd4c449310f5f1697d348e42d1819eaef69080e33e7652d7393521ed50d7427a0e", "version": 1, - "signer": SDK_PY_SIGNER + "signer": SDK_PY_SIGNER, } unpacked_message = message_computer.unpack_message(packed_message) @@ -46,7 +44,10 @@ def test_sign_packed_message_and_verify_unpacked_message(): assert unpacked_message.version == message.version verifier = UserVerifier.from_address(unpacked_message.address) - assert verifier.verify(message_computer.compute_bytes_for_verifying(unpacked_message), unpacked_message.signature) + assert verifier.verify( + message_computer.compute_bytes_for_verifying(unpacked_message), + unpacked_message.signature, + ) def test_unpack_legacy_message(): @@ -55,14 +56,17 @@ def test_unpack_legacy_message(): "message": "0x7468697320697320612074657374206d657373616765", "signature": "0xb16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809", "version": 1, - "signer": "ErdJS" + "signer": "ErdJS", } message = message_computer.unpack_message(legacy_message) assert message.address assert message.address.to_bech32() == alice.to_bech32() assert message.data.decode() == "this is a test message" - assert message.signature.hex() == "b16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809" + assert ( + message.signature.hex() + == "b16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809" + ) assert message.version == 1 assert message.signer == "ErdJS" @@ -71,13 +75,16 @@ def test_unpack_message(): packed_message = { "address": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", "message": "0x7468697320697320612074657374206d657373616765", - "signature": "0xb16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809" + "signature": "0xb16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809", } message = message_computer.unpack_message(packed_message) assert message.address assert message.address.to_bech32() == alice.to_bech32() assert message.data.decode() == "this is a test message" - assert message.signature.hex() == "b16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809" + assert ( + message.signature.hex() + == "b16847437049986f936dd4a0917c869730cbf29e40a0c0821ca70db33f44758c3d41bcbea446dee70dea13d50942343bb78e74979dc434bbb2b901e0f4fd1809" + ) assert message.version == 1 assert message.signer == UNKNOWN_SIGNER diff --git a/multiversx_sdk/core/proto/transaction_serializer_test.py b/multiversx_sdk/core/proto/transaction_serializer_test.py index d92ee727..e932f17f 100644 --- a/multiversx_sdk/core/proto/transaction_serializer_test.py +++ b/multiversx_sdk/core/proto/transaction_serializer_test.py @@ -1,10 +1,9 @@ +from multiversx_sdk.core.address import Address from multiversx_sdk.core.proto.transaction_serializer import ProtoSerializer from multiversx_sdk.core.transaction import Transaction from multiversx_sdk.core.transaction_computer import TransactionComputer from multiversx_sdk.testutils.wallets import load_wallets -from multiversx_sdk.core.address import Address - class TestProtoSerializer: wallets = load_wallets() @@ -23,10 +22,15 @@ def test_serialize_tx_no_data_no_value(self): nonce=89, value=0, ) - transaction.signature = self.alice.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(transaction)) + transaction.signature = self.alice.secret_key.sign( + self.transaction_computer.compute_bytes_for_signing(transaction) + ) serialized_transaction = self.proto_serializer.serialize_transaction(transaction) - assert serialized_transaction.hex() == "0859120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc0340d08603520d6c6f63616c2d746573746e6574580262403f08a1dd64fbb627d10b048e0b45b1390f29bb0e457762a2ccb710b029f299022a67a4b8e45cf62f4314afec2e56b5574c71e38df96cc41fae757b7ee5062503" + assert ( + serialized_transaction.hex() + == "0859120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc0340d08603520d6c6f63616c2d746573746e6574580262403f08a1dd64fbb627d10b048e0b45b1390f29bb0e457762a2ccb710b029f299022a67a4b8e45cf62f4314afec2e56b5574c71e38df96cc41fae757b7ee5062503" + ) def test_serialize_tx_with_data_no_value(self): transaction = Transaction( @@ -35,12 +39,17 @@ def test_serialize_tx_with_data_no_value(self): gas_limit=80000, chain_id="local-testnet", data=b"hello", - nonce=90 + nonce=90, + ) + transaction.signature = self.alice.secret_key.sign( + self.transaction_computer.compute_bytes_for_signing(transaction) ) - transaction.signature = self.alice.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(transaction)) serialized_transaction = self.proto_serializer.serialize_transaction(transaction) - assert serialized_transaction.hex() == "085a120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc034080f1044a0568656c6c6f520d6c6f63616c2d746573746e657458026240f9e8c1caf7f36b99e7e76ee1118bf71b55cde11a2356e2b3adf15f4ad711d2e1982469cbba7eb0afbf74e8a8f78e549b9410cd86eeaa88fcba62611ac9f6e30e" + assert ( + serialized_transaction.hex() + == "085a120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc034080f1044a0568656c6c6f520d6c6f63616c2d746573746e657458026240f9e8c1caf7f36b99e7e76ee1118bf71b55cde11a2356e2b3adf15f4ad711d2e1982469cbba7eb0afbf74e8a8f78e549b9410cd86eeaa88fcba62611ac9f6e30e" + ) def test_serialize_tx_with_data_and_value(self): transaction = Transaction( @@ -50,12 +59,17 @@ def test_serialize_tx_with_data_and_value(self): chain_id="local-testnet", nonce=92, data=b"for the spaceship", - value=123456789000000000000000000000 + value=123456789000000000000000000000, + ) + transaction.signature = self.alice.secret_key.sign( + self.transaction_computer.compute_bytes_for_signing(transaction) ) - transaction.signature = self.alice.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(transaction)) serialized_transaction = self.proto_serializer.serialize_transaction(transaction) - assert serialized_transaction.hex() == "085c120e00018ee90ff6181f3761632000001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc0340a08d064a11666f722074686520737061636573686970520d6c6f63616c2d746573746e65745802624001f05aa8cb0614e12a94ab9dcbde5e78370a4e05d23ef25a1fb9d5fcf1cb3b1f33b919cd8dafb1704efb18fa233a8aa0d3344fb6ee9b613a7d7a403786ffbd0a" + assert ( + serialized_transaction.hex() + == "085c120e00018ee90ff6181f3761632000001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc0340a08d064a11666f722074686520737061636573686970520d6c6f63616c2d746573746e65745802624001f05aa8cb0614e12a94ab9dcbde5e78370a4e05d23ef25a1fb9d5fcf1cb3b1f33b919cd8dafb1704efb18fa233a8aa0d3344fb6ee9b613a7d7a403786ffbd0a" + ) def test_serialize_tx_with_nonce_zero(self): transaction = Transaction( @@ -66,12 +80,17 @@ def test_serialize_tx_with_nonce_zero(self): nonce=0, value=0, data=b"hello", - version=1 + version=1, + ) + transaction.signature = self.alice.secret_key.sign( + self.transaction_computer.compute_bytes_for_signing(transaction) ) - transaction.signature = self.alice.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(transaction)) serialized_transaction = self.proto_serializer.serialize_transaction(transaction) - assert serialized_transaction.hex() == "120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc034080f1044a0568656c6c6f520d6c6f63616c2d746573746e657458016240dfa3e9f2fdec60dcb353bac3b3435b4a2ff251e7e98eaf8620f46c731fc70c8ba5615fd4e208b05e75fe0f7dc44b7a99567e29f94fcd91efac7e67b182cd2a04" + assert ( + serialized_transaction.hex() + == "120200001a208049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f82a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1388094ebdc034080f1044a0568656c6c6f520d6c6f63616c2d746573746e657458016240dfa3e9f2fdec60dcb353bac3b3435b4a2ff251e7e98eaf8620f46c731fc70c8ba5615fd4e208b05e75fe0f7dc44b7a99567e29f94fcd91efac7e67b182cd2a04" + ) def test_serialized_tx_with_usernames(self): transaction = Transaction( @@ -82,9 +101,14 @@ def test_serialized_tx_with_usernames(self): nonce=204, value=1000000000000000000, sender_username="carol", - receiver_username="alice" + receiver_username="alice", + ) + transaction.signature = self.carol.secret_key.sign( + self.transaction_computer.compute_bytes_for_signing(transaction) ) - transaction.signature = self.carol.secret_key.sign(self.transaction_computer.compute_bytes_for_signing(transaction)) serialized_transaction = self.proto_serializer.serialize_transaction(transaction) - assert serialized_transaction.hex() == "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06" + assert ( + serialized_transaction.hex() + == "08cc011209000de0b6b3a76400001a200139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e12205616c6963652a20b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba32056361726f6c388094ebdc0340d086035201545802624051e6cd78fb3ab4b53ff7ad6864df27cb4a56d70603332869d47a5cf6ea977c30e696103e41e8dddf2582996ad335229fdf4acb726564dbc1a0bc9e705b511f06" + ) diff --git a/multiversx_sdk/core/tokens.py b/multiversx_sdk/core/tokens.py index bb18d5cf..aec5c493 100644 --- a/multiversx_sdk/core/tokens.py +++ b/multiversx_sdk/core/tokens.py @@ -3,9 +3,10 @@ from multiversx_sdk.abi.biguint_value import BigUIntValue from multiversx_sdk.abi.serializer import Serializer from multiversx_sdk.core.constants import ( - EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER, TOKEN_RANDOM_SEQUENCE_LENGTH) -from multiversx_sdk.core.errors import (BadUsageError, - InvalidTokenIdentifierError) + EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER, + TOKEN_RANDOM_SEQUENCE_LENGTH, +) +from multiversx_sdk.core.errors import BadUsageError, InvalidTokenIdentifierError class Token: @@ -27,7 +28,13 @@ def new_from_native_amount(amount: int) -> "TokenTransfer": class TokenIdentifierParts: - def __init__(self, ticker: str, random_sequence: str, nonce: int, prefix: Union[str, None] = None) -> None: + def __init__( + self, + ticker: str, + random_sequence: str, + nonce: int, + prefix: Union[str, None] = None, + ) -> None: self.ticker = ticker self.random_sequence = random_sequence self.nonce = nonce @@ -67,7 +74,13 @@ def _split_identifier_into_components(self, token_parts: list[str]) -> tuple[Uni return token_parts[0], token_parts[1], token_parts[2] return None, token_parts[0], token_parts[1] - def _validate_extended_identifier(self, prefix: Union[str, None], ticker: str, random_sequence: str, parts: list[str]) -> None: + def _validate_extended_identifier( + self, + prefix: Union[str, None], + ticker: str, + random_sequence: str, + parts: list[str], + ) -> None: self._check_if_extended_identifier_was_provided(prefix, parts) self._ensure_token_prefix_validity(prefix) self._ensure_token_ticker_validity(ticker) @@ -140,7 +153,10 @@ def _check_if_extended_identifier_was_provided(self, token_prefx: Union[str, Non # this is for the identifiers of nft, sft and meta-esdt MAX_EXTENDED_IDENTIFIER_LENGTH_IF_SPLIT = 3 if not token_prefx else 4 - if len(token_parts) < MIN_EXTENDED_IDENTIFIER_LENGTH_IF_SPLIT or len(token_parts) > MAX_EXTENDED_IDENTIFIER_LENGTH_IF_SPLIT: + if ( + len(token_parts) < MIN_EXTENDED_IDENTIFIER_LENGTH_IF_SPLIT + or len(token_parts) > MAX_EXTENDED_IDENTIFIER_LENGTH_IF_SPLIT + ): raise InvalidTokenIdentifierError("Invalid extended token identifier provided") def _ensure_token_ticker_validity(self, ticker: str) -> None: @@ -148,7 +164,9 @@ def _ensure_token_ticker_validity(self, ticker: str) -> None: MAX_TICKER_LENGTH = 10 if len(ticker) < MIN_TICKER_LENGTH or len(ticker) > MAX_TICKER_LENGTH: - raise InvalidTokenIdentifierError(f"The token ticker should be between {MIN_TICKER_LENGTH} and {MAX_TICKER_LENGTH} characters") + raise InvalidTokenIdentifierError( + f"The token ticker should be between {MIN_TICKER_LENGTH} and {MAX_TICKER_LENGTH} characters" + ) if not ticker.isalnum(): raise InvalidTokenIdentifierError("The token ticker should only contain alphanumeric characters") @@ -159,7 +177,8 @@ def _ensure_token_ticker_validity(self, ticker: str) -> None: def _check_length_of_random_sequence(self, random_sequence: str) -> None: if len(random_sequence) != TOKEN_RANDOM_SEQUENCE_LENGTH: raise InvalidTokenIdentifierError( - "The identifier is not valid. The random sequence does not have the right length") + "The identifier is not valid. The random sequence does not have the right length" + ) def _ensure_token_prefix_validity(self, prefix: Union[str, None]) -> None: MIN_TOKEN_PREFIX_LENGTH = 1 diff --git a/multiversx_sdk/core/tokens_test.py b/multiversx_sdk/core/tokens_test.py index 6cea4f2d..84faf267 100644 --- a/multiversx_sdk/core/tokens_test.py +++ b/multiversx_sdk/core/tokens_test.py @@ -1,8 +1,12 @@ import pytest from multiversx_sdk.core.errors import BadUsageError -from multiversx_sdk.core.tokens import (Token, TokenComputer, - TokenIdentifierParts, TokenTransfer) +from multiversx_sdk.core.tokens import ( + Token, + TokenComputer, + TokenIdentifierParts, + TokenTransfer, +) class TestTokenComputer: @@ -33,18 +37,27 @@ def test_extract_identifier_from_extended_identifier(self): extended_fungible_identifier = "FNG-123456" assert self.token_computer.extract_identifier_from_extended_identifier(extended_nft_identifier) == "TEST-123456" - assert self.token_computer.extract_identifier_from_extended_identifier( - extended_fungible_identifier) == "FNG-123456" + assert ( + self.token_computer.extract_identifier_from_extended_identifier(extended_fungible_identifier) + == "FNG-123456" + ) extended_identifier_with_prefix = "test-TEST-123456-0a" - assert self.token_computer.extract_identifier_from_extended_identifier( - extended_identifier_with_prefix) == "test-TEST-123456" + assert ( + self.token_computer.extract_identifier_from_extended_identifier(extended_identifier_with_prefix) + == "test-TEST-123456" + ) fungible_identifier_with_prefix = "test-FNG-123456" - assert self.token_computer.extract_identifier_from_extended_identifier( - fungible_identifier_with_prefix) == "test-FNG-123456" + assert ( + self.token_computer.extract_identifier_from_extended_identifier(fungible_identifier_with_prefix) + == "test-FNG-123456" + ) - with pytest.raises(Exception, match="Token prefix is invalid, it does not have the right length"): + with pytest.raises( + Exception, + match="Token prefix is invalid, it does not have the right length", + ): self.token_computer.extract_identifier_from_extended_identifier("prefix-TEST-123456") def test_extract_ticker_from_identifier(self): @@ -101,7 +114,10 @@ def test_compute_extended_identifier_from_identifier_and_nonce(self): assert fungible_token_identifier == "FNG-123456" assert nft_identifier == "NFT-987654-0a" - assert self.token_computer.compute_extended_identifier_from_identifier_and_nonce("test-NFT-123456", 10) == "test-NFT-123456-0a" + assert ( + self.token_computer.compute_extended_identifier_from_identifier_and_nonce("test-NFT-123456", 10) + == "test-NFT-123456-0a" + ) def test_compute_extended_identifier_from_parts(self): fungible_parts = TokenIdentifierParts("FNG", "123456", 0) diff --git a/multiversx_sdk/core/transaction.py b/multiversx_sdk/core/transaction.py index dc0c751d..0c8a6d27 100644 --- a/multiversx_sdk/core/transaction.py +++ b/multiversx_sdk/core/transaction.py @@ -2,30 +2,34 @@ from typing import Any, Optional, Union from multiversx_sdk.core.address import Address -from multiversx_sdk.core.constants import (TRANSACTION_MIN_GAS_PRICE, - TRANSACTION_OPTIONS_DEFAULT, - TRANSACTION_VERSION_DEFAULT) +from multiversx_sdk.core.constants import ( + TRANSACTION_MIN_GAS_PRICE, + TRANSACTION_OPTIONS_DEFAULT, + TRANSACTION_VERSION_DEFAULT, +) class Transaction: - def __init__(self, - sender: Address, - receiver: Address, - gas_limit: int, - chain_id: str, - nonce: Optional[int] = None, - value: Optional[int] = None, - sender_username: Optional[str] = None, - receiver_username: Optional[str] = None, - gas_price: Optional[int] = None, - data: Optional[bytes] = None, - version: Optional[int] = None, - options: Optional[int] = None, - guardian: Optional[Address] = None, - signature: Optional[bytes] = None, - guardian_signature: Optional[bytes] = None, - relayer: Optional[Address] = None, - relayer_signature: Optional[bytes] = None) -> None: + def __init__( + self, + sender: Address, + receiver: Address, + gas_limit: int, + chain_id: str, + nonce: Optional[int] = None, + value: Optional[int] = None, + sender_username: Optional[str] = None, + receiver_username: Optional[str] = None, + gas_price: Optional[int] = None, + data: Optional[bytes] = None, + version: Optional[int] = None, + options: Optional[int] = None, + guardian: Optional[Address] = None, + signature: Optional[bytes] = None, + guardian_signature: Optional[bytes] = None, + relayer: Optional[Address] = None, + relayer_signature: Optional[bytes] = None, + ) -> None: self.chain_id = chain_id self.sender = sender self.receiver = receiver @@ -67,7 +71,7 @@ def to_dictionary(self) -> dict[str, Any]: "signature": self._value_to_hex_or_empty(self.signature), "guardianSignature": self._value_to_hex_or_empty(self.guardian_signature), "relayer": self.relayer.to_bech32() if self.relayer else "", - "relayerSignature": self._value_to_hex_or_empty(self.relayer_signature) + "relayerSignature": self._value_to_hex_or_empty(self.relayer_signature), } @staticmethod @@ -99,7 +103,7 @@ def new_from_dictionary(dictionary: dict[str, Any]) -> "Transaction": signature=_bytes_from_hex(dictionary.get("signature", "")), guardian_signature=_bytes_from_hex(dictionary.get("guardianSignature", "")), relayer=relayer, - relayer_signature=_bytes_from_hex(dictionary.get("relayerSignature", "")) + relayer_signature=_bytes_from_hex(dictionary.get("relayerSignature", "")), ) def _value_to_b64_or_empty(self, value: Union[str, bytes]) -> str: diff --git a/multiversx_sdk/core/transaction_events_parser_test.py b/multiversx_sdk/core/transaction_events_parser_test.py index 72662f93..069c59f1 100644 --- a/multiversx_sdk/core/transaction_events_parser_test.py +++ b/multiversx_sdk/core/transaction_events_parser_test.py @@ -8,14 +8,18 @@ from multiversx_sdk.abi.serializer import Serializer from multiversx_sdk.abi.small_int_values import U64Value from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transaction_events_parser import \ - TransactionEventsParser +from multiversx_sdk.core.transaction_events_parser import TransactionEventsParser from multiversx_sdk.core.transaction_on_network import ( - TransactionEvent, TransactionLogs, find_events_by_first_topic, - find_events_by_identifier) + TransactionEvent, + TransactionLogs, + find_events_by_first_topic, + find_events_by_identifier, +) 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) + get_empty_smart_contract_result, + get_empty_transaction_on_network, +) testdata = Path(__file__).parent.parent / "testutils" / "testdata" @@ -29,17 +33,14 @@ def test_parse_events_minimalistic(): raw={}, address=Address.empty(), identifier="transferOverMaxAmount", - topics=["transferOverMaxAmount".encode(), bytes([0x2a]), bytes([0x2b])], + topics=["transferOverMaxAmount".encode(), bytes([0x2A]), bytes([0x2B])], data=b"", - additional_data=[] + additional_data=[], ) ] ) assert len(values) == 1 - assert values[0] == SimpleNamespace( - batch_id=42, - tx_id=43 - ) + assert values[0] == SimpleNamespace(batch_id=42, tx_id=43) def test_parse_esdt_safe_deposit_event(): @@ -58,12 +59,12 @@ def test_parse_esdt_safe_deposit_event(): topics=[ bytes.fromhex("6465706f736974"), bytes.fromhex("726cc2d4b46dd6bd74a4c84d02715bf85cae76318cab81bc09e7c261d4149a67"), - bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164") + bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164"), ], data=b"", - additional_data=[bytes.fromhex("00000000000003db000000")] + additional_data=[bytes.fromhex("00000000000003db000000")], ) - ] + ], ) sc_result = get_empty_smart_contract_result() @@ -77,18 +78,15 @@ def test_parse_esdt_safe_deposit_event(): assert len(parsed) == 1 assert parsed[0] == SimpleNamespace( dest_address=Address.new_from_bech32( - "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), - tokens=[SimpleNamespace( - token_identifier="WEGLD-01e49d", - token_nonce=0, - amount=100 - )], + "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun" + ).get_public_key(), + tokens=[SimpleNamespace(token_identifier="WEGLD-01e49d", token_nonce=0, amount=100)], event_data=SimpleNamespace( tx_nonce=987, opt_function=None, opt_arguments=None, opt_gas_limit=None, - ) + ), ) @@ -100,15 +98,23 @@ def test_parse_multisig_start_perform_action(): 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={}, + transaction.logs = TransactionLogs( address=Address.empty(), - identifier="performAction", - topics=[bytes.fromhex("7374617274506572666f726d416374696f6e")], - data=b"", - additional_data=[bytes.fromhex( - "00000001000000000500000000000000000500d006f73c4221216fa679bc559005584c4f1160e569e1000000000000000003616464000000010000000107000000010139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1")] - )]) + events=[ + TransactionEvent( + raw={}, + address=Address.empty(), + identifier="performAction", + topics=[bytes.fromhex("7374617274506572666f726d416374696f6e")], + data=b"", + additional_data=[ + bytes.fromhex( + "00000001000000000500000000000000000500d006f73c4221216fa679bc559005584c4f1160e569e1000000000000000003616464000000010000000107000000010139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" + ) + ], + ) + ], + ) events = find_events_by_first_topic(transaction, "startPerformAction") parsed = parser.parse_events(events) @@ -121,17 +127,19 @@ def test_parse_multisig_start_perform_action(): **{ "0": SimpleNamespace( to=Address.new_from_bech32( - "erd1qqqqqqqqqqqqqpgq6qr0w0zzyysklfneh32eqp2cf383zc89d8sstnkl60").get_public_key(), + "erd1qqqqqqqqqqqqqpgq6qr0w0zzyysklfneh32eqp2cf383zc89d8sstnkl60" + ).get_public_key(), egld_amount=0, opt_gas_limit=None, - endpoint_name=b'add', - arguments=[bytes.fromhex("07")] + endpoint_name=b"add", + arguments=[bytes.fromhex("07")], ), - '__discriminant__': 5 + "__discriminant__": 5, } ), - signers=[Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key()] + signers=[ + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key() + ], ) @@ -165,9 +173,7 @@ def test_parse_event_with_multi_values(): abi = Abi(abi_definition) parser = TransactionEventsParser(abi=abi) serializer = Serializer() - first_value, second_value, third_value = serializer.serialize_to_parts( - [U64Value(42), U64Value(43), U64Value(44)] - ) + first_value, second_value, third_value = serializer.serialize_to_parts([U64Value(42), U64Value(43), U64Value(44)]) parsed = parser.parse_event( TransactionEvent( @@ -184,15 +190,11 @@ def test_parse_event_with_multi_values(): third_value, ], data=b"", - additional_data=[first_value] + additional_data=[first_value], ) ) - assert parsed == SimpleNamespace( - a=[42, "test", 43, "test"], - b=["test", 44], - c=42 - ) + assert parsed == SimpleNamespace(a=[42, "test", 43, "test"], b=["test", 44], c=42) def test_parse_esdt_safe_deposit_event_without_first_topic(): @@ -211,12 +213,12 @@ def test_parse_esdt_safe_deposit_event_without_first_topic(): topics=[ bytes.fromhex(""), bytes.fromhex("726cc2d4b46dd6bd74a4c84d02715bf85cae76318cab81bc09e7c261d4149a67"), - bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164") + bytes.fromhex("0000000c5745474c442d30316534396400000000000000000000000164"), ], data=b"", - additional_data=[bytes.fromhex("00000000000003db000000")] + additional_data=[bytes.fromhex("00000000000003db000000")], ) - ] + ], ) sc_result = get_empty_smart_contract_result() @@ -230,18 +232,15 @@ def test_parse_esdt_safe_deposit_event_without_first_topic(): assert len(parsed) == 1 assert parsed[0] == SimpleNamespace( dest_address=Address.new_from_bech32( - "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun").get_public_key(), - tokens=[SimpleNamespace( - token_identifier="WEGLD-01e49d", - token_nonce=0, - amount=100 - )], + "erd1wfkv9495dhtt6a9yepxsyu2mlpw2ua333j4cr0qfulpxr4q5nfnshgyqun" + ).get_public_key(), + tokens=[SimpleNamespace(token_identifier="WEGLD-01e49d", token_nonce=0, amount=100)], event_data=SimpleNamespace( tx_nonce=987, opt_function=None, opt_arguments=None, opt_gas_limit=None, - ) + ), ) @@ -275,16 +274,20 @@ def test_multisig_start_perform_action(): **{ "0": SimpleNamespace( **{ - 'to': Address.new_from_bech32("erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede").get_public_key(), - 'egld_amount': 1000000000000000000, - 'opt_gas_limit': None, - 'endpoint_name': b'', - 'arguments': [] + "to": Address.new_from_bech32( + "erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede" + ).get_public_key(), + "egld_amount": 1000000000000000000, + "opt_gas_limit": None, + "endpoint_name": b"", + "arguments": [], } ), - '__discriminant__': 5 + "__discriminant__": 5, }, ), - signers=[Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key(), - Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx").get_public_key()] + signers=[ + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th").get_public_key(), + Address.new_from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx").get_public_key(), + ], ) diff --git a/multiversx_sdk/core/transaction_on_network.py b/multiversx_sdk/core/transaction_on_network.py index a8fae619..4aabec37 100644 --- a/multiversx_sdk/core/transaction_on_network.py +++ b/multiversx_sdk/core/transaction_on_network.py @@ -76,8 +76,7 @@ def is_topic_matching(event: TransactionEvent): def find_events_by_predicate( - transaction: TransactionOnNetwork, - predicate: Callable[[TransactionEvent], bool] + transaction: TransactionOnNetwork, predicate: Callable[[TransactionEvent], bool] ) -> list[TransactionEvent]: events = gather_all_events(transaction) return list(filter(predicate, events)) diff --git a/multiversx_sdk/core/transaction_status.py b/multiversx_sdk/core/transaction_status.py index 6f887857..4718fe7f 100644 --- a/multiversx_sdk/core/transaction_status.py +++ b/multiversx_sdk/core/transaction_status.py @@ -16,7 +16,12 @@ def _is_status_completed(self) -> bool: return self._is_status_successful() or self._is_failed() def _is_status_successful(self) -> bool: - return self.status == 'executed' or self.status == 'success' or self.status == 'successful' + return self.status == "executed" or self.status == "success" or self.status == "successful" def _is_failed(self) -> bool: - return self.status == 'fail' or self.status == 'failed' or self.status == 'unsuccessful' or self.status == "invalid" + return ( + self.status == "fail" + or self.status == "failed" + or self.status == "unsuccessful" + or self.status == "invalid" + ) diff --git a/multiversx_sdk/core/transaction_test.py b/multiversx_sdk/core/transaction_test.py index 2aeeb0b7..798ad61f 100644 --- a/multiversx_sdk/core/transaction_test.py +++ b/multiversx_sdk/core/transaction_test.py @@ -345,12 +345,14 @@ def test_compute_bytes_for_verifying_signature(self): user_verifier = UserVerifier(self.alice.public_key) is_signed_by_alice = user_verifier.verify( - data=self.transaction_computer.compute_bytes_for_verifying(tx), signature=tx.signature + data=self.transaction_computer.compute_bytes_for_verifying(tx), + signature=tx.signature, ) wrong_verifier = UserVerifier(self.bob.public_key) is_signed_by_bob = wrong_verifier.verify( - data=self.transaction_computer.compute_bytes_for_verifying(tx), signature=tx.signature + data=self.transaction_computer.compute_bytes_for_verifying(tx), + signature=tx.signature, ) assert is_signed_by_alice @@ -369,12 +371,14 @@ def test_compute_bytes_for_verifying_transaction_signed_by_hash(self): user_verifier = UserVerifier(self.alice.public_key) is_signed_by_alice = user_verifier.verify( - data=self.transaction_computer.compute_bytes_for_verifying(tx), signature=tx.signature + data=self.transaction_computer.compute_bytes_for_verifying(tx), + signature=tx.signature, ) wrong_verifier = UserVerifier(self.bob.public_key) is_signed_by_bob = wrong_verifier.verify( - data=self.transaction_computer.compute_bytes_for_verifying(tx), signature=tx.signature + data=self.transaction_computer.compute_bytes_for_verifying(tx), + signature=tx.signature, ) assert is_signed_by_alice diff --git a/multiversx_sdk/core/transactions_factory_config.py b/multiversx_sdk/core/transactions_factory_config.py index c0813e8d..774fc40d 100644 --- a/multiversx_sdk/core/transactions_factory_config.py +++ b/multiversx_sdk/core/transactions_factory_config.py @@ -44,7 +44,9 @@ class TransactionsFactoryConfig: gas_limit_stop_nft_create: int = 60_000_000 gas_limit_wipe_single_nft: int = 60_000_000 gas_limit_esdt_nft_add_uri: int = 10_000_000 - esdt_contract_address: Address = field(default_factory=lambda: Address.new_from_hex(value=ESDT_CONTRACT_ADDRESS_HEX)) + esdt_contract_address: Address = field( + default_factory=lambda: Address.new_from_hex(value=ESDT_CONTRACT_ADDRESS_HEX) + ) # Configuration for delegation operations gas_limit_stake: int = 5_000_000 diff --git a/multiversx_sdk/delegation/__init__.py b/multiversx_sdk/delegation/__init__.py index daf82f84..f1d8f02c 100644 --- a/multiversx_sdk/delegation/__init__.py +++ b/multiversx_sdk/delegation/__init__.py @@ -1,13 +1,17 @@ -from multiversx_sdk.delegation.delegation_controller import \ - DelegationController -from multiversx_sdk.delegation.delegation_transactions_factory import \ - DelegationTransactionsFactory -from multiversx_sdk.delegation.delegation_transactions_outcome_parser import \ - DelegationTransactionsOutcomeParser -from multiversx_sdk.delegation.delegation_transactions_outcome_parser_types import \ - CreateNewDelegationContractOutcome +from multiversx_sdk.delegation.delegation_controller import DelegationController +from multiversx_sdk.delegation.delegation_transactions_factory import ( + DelegationTransactionsFactory, +) +from multiversx_sdk.delegation.delegation_transactions_outcome_parser import ( + DelegationTransactionsOutcomeParser, +) +from multiversx_sdk.delegation.delegation_transactions_outcome_parser_types import ( + CreateNewDelegationContractOutcome, +) __all__ = [ - "DelegationController", "DelegationTransactionsFactory", - "DelegationTransactionsOutcomeParser", "CreateNewDelegationContractOutcome" + "DelegationController", + "DelegationTransactionsFactory", + "DelegationTransactionsOutcomeParser", + "CreateNewDelegationContractOutcome", ] diff --git a/multiversx_sdk/delegation/delegation_controller.py b/multiversx_sdk/delegation/delegation_controller.py index 4c629816..522e9f4d 100644 --- a/multiversx_sdk/delegation/delegation_controller.py +++ b/multiversx_sdk/delegation/delegation_controller.py @@ -107,7 +107,9 @@ def create_transaction_for_removing_nodes( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_removing_nodes( - sender=sender.address, delegation_contract=delegation_contract, public_keys=public_keys + sender=sender.address, + delegation_contract=delegation_contract, + public_keys=public_keys, ) transaction.guardian = guardian @@ -129,7 +131,9 @@ def create_transaction_for_staking_nodes( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_staking_nodes( - sender=sender.address, delegation_contract=delegation_contract, public_keys=public_keys + sender=sender.address, + delegation_contract=delegation_contract, + public_keys=public_keys, ) transaction.guardian = guardian @@ -151,7 +155,9 @@ def create_transaction_for_unbonding_nodes( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_unbonding_nodes( - sender=sender.address, delegation_contract=delegation_contract, public_keys=public_keys + sender=sender.address, + delegation_contract=delegation_contract, + public_keys=public_keys, ) transaction.guardian = guardian @@ -173,7 +179,9 @@ def create_transaction_for_unstaking_nodes( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_unstaking_nodes( - sender=sender.address, delegation_contract=delegation_contract, public_keys=public_keys + sender=sender.address, + delegation_contract=delegation_contract, + public_keys=public_keys, ) transaction.guardian = guardian @@ -221,7 +229,9 @@ def create_transaction_for_changing_service_fee( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_changing_service_fee( - sender=sender.address, delegation_contract=delegation_contract, service_fee=service_fee + sender=sender.address, + delegation_contract=delegation_contract, + service_fee=service_fee, ) transaction.guardian = guardian @@ -379,7 +389,9 @@ def create_transaction_for_delegating( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_delegating( - sender=sender.address, delegation_contract=delegation_contract, amount=amount + sender=sender.address, + delegation_contract=delegation_contract, + amount=amount, ) transaction.guardian = guardian @@ -443,7 +455,9 @@ def create_transaction_for_undelegating( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_undelegating( - sender=sender.address, delegation_contract=delegation_contract, amount=amount + sender=sender.address, + delegation_contract=delegation_contract, + amount=amount, ) transaction.guardian = guardian diff --git a/multiversx_sdk/delegation/delegation_transactions_factory.py b/multiversx_sdk/delegation/delegation_transactions_factory.py index eb0dc523..75846f8d 100644 --- a/multiversx_sdk/delegation/delegation_transactions_factory.py +++ b/multiversx_sdk/delegation/delegation_transactions_factory.py @@ -6,8 +6,7 @@ from multiversx_sdk.builders.transaction_builder import TransactionBuilder from multiversx_sdk.core import Address, Transaction from multiversx_sdk.core.constants import DELEGATION_MANAGER_SC_ADDRESS_HEX -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.delegation.errors import ListsLengthMismatchError from multiversx_sdk.wallet.validator_keys import ValidatorPublicKey @@ -17,17 +16,14 @@ def __init__(self, config: TransactionsFactoryConfig) -> None: self.config = config self.serializer = Serializer() - def create_transaction_for_new_delegation_contract(self, - sender: Address, - total_delegation_cap: int, - service_fee: int, - amount: int) -> Transaction: + def create_transaction_for_new_delegation_contract( + self, sender: Address, total_delegation_cap: int, service_fee: int, amount: int + ) -> Transaction: parts = ["createNewDelegationContract"] - serialized_parts = self.serializer.serialize_to_parts([ - BigUIntValue(total_delegation_cap), - BigUIntValue(service_fee) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [BigUIntValue(total_delegation_cap), BigUIntValue(service_fee)] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -36,18 +32,21 @@ def create_transaction_for_new_delegation_contract(self, sender=sender, receiver=Address.new_from_hex(DELEGATION_MANAGER_SC_ADDRESS_HEX), data_parts=parts, - gas_limit=self.config.gas_limit_create_delegation_contract + self.config.additional_gas_for_delegation_operations, + gas_limit=self.config.gas_limit_create_delegation_contract + + self.config.additional_gas_for_delegation_operations, add_data_movement_gas=True, - amount=amount + amount=amount, ).build() return transaction - def create_transaction_for_adding_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey], - signed_messages: Sequence[bytes]) -> Transaction: + def create_transaction_for_adding_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + signed_messages: Sequence[bytes], + ) -> Transaction: if len(public_keys) != len(signed_messages): raise ListsLengthMismatchError("The number of public keys should match the number of signed messages") @@ -64,18 +63,23 @@ def create_transaction_for_adding_nodes(self, receiver=delegation_contract, data_parts=parts, gas_limit=self._compute_execution_gas_limit_for_nodes_management(num_nodes), - add_data_movement_gas=True + add_data_movement_gas=True, ).build() return transaction def _compute_execution_gas_limit_for_nodes_management(self, num_nodes: int) -> int: - return self.config.gas_limit_delegation_operations + num_nodes * self.config.additional_gas_limit_per_validator_node - - def create_transaction_for_removing_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey]) -> Transaction: + return ( + self.config.gas_limit_delegation_operations + + num_nodes * self.config.additional_gas_limit_per_validator_node + ) + + def create_transaction_for_removing_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + ) -> Transaction: num_nodes = len(public_keys) parts = ["removeNodes"] @@ -88,15 +92,17 @@ def create_transaction_for_removing_nodes(self, receiver=delegation_contract, data_parts=parts, gas_limit=self._compute_execution_gas_limit_for_nodes_management(num_nodes), - add_data_movement_gas=True + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_staking_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey]) -> Transaction: + def create_transaction_for_staking_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + ) -> Transaction: num_nodes = len(public_keys) parts = ["stakeNodes"] @@ -108,17 +114,20 @@ def create_transaction_for_staking_nodes(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.gas_limit_stake + - num_nodes * self.config.additional_gas_limit_per_validator_node, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.gas_limit_stake + + num_nodes * self.config.additional_gas_limit_per_validator_node, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_unbonding_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey]) -> Transaction: + def create_transaction_for_unbonding_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + ) -> Transaction: num_nodes = len(public_keys) parts = ["unBondNodes"] @@ -130,17 +139,20 @@ def create_transaction_for_unbonding_nodes(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.gas_limit_unbond + - num_nodes * self.config.additional_gas_limit_per_validator_node, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.gas_limit_unbond + + num_nodes * self.config.additional_gas_limit_per_validator_node, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_unstaking_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey]) -> Transaction: + def create_transaction_for_unstaking_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + ) -> Transaction: num_nodes = len(public_keys) parts = ["unStakeNodes"] @@ -152,18 +164,21 @@ def create_transaction_for_unstaking_nodes(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.gas_limit_unstake + - num_nodes * self.config.additional_gas_limit_per_validator_node, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.gas_limit_unstake + + num_nodes * self.config.additional_gas_limit_per_validator_node, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_unjailing_nodes(self, - sender: Address, - delegation_contract: Address, - public_keys: Sequence[ValidatorPublicKey], - amount: int) -> Transaction: + def create_transaction_for_unjailing_nodes( + self, + sender: Address, + delegation_contract: Address, + public_keys: Sequence[ValidatorPublicKey], + amount: int, + ) -> Transaction: num_nodes = len(public_keys) parts = ["unJailNodes"] @@ -177,18 +192,17 @@ def create_transaction_for_unjailing_nodes(self, data_parts=parts, gas_limit=self._compute_execution_gas_limit_for_nodes_management(num_nodes), add_data_movement_gas=True, - amount=amount + amount=amount, ).build() return transaction - def create_transaction_for_changing_service_fee(self, - sender: Address, - delegation_contract: Address, - service_fee: int) -> Transaction: + def create_transaction_for_changing_service_fee( + self, sender: Address, delegation_contract: Address, service_fee: int + ) -> Transaction: parts = [ "changeServiceFee", - self.serializer.serialize([BigUIntValue(service_fee)]) + self.serializer.serialize([BigUIntValue(service_fee)]), ] transaction = TransactionBuilder( @@ -196,19 +210,19 @@ def create_transaction_for_changing_service_fee(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_modifying_delegation_cap(self, - sender: Address, - delegation_contract: Address, - delegation_cap: int) -> Transaction: + def create_transaction_for_modifying_delegation_cap( + self, sender: Address, delegation_contract: Address, delegation_cap: int + ) -> Transaction: parts = [ "modifyTotalDelegationCap", - self.serializer.serialize([BigUIntValue(delegation_cap)]) + self.serializer.serialize([BigUIntValue(delegation_cap)]), ] transaction = TransactionBuilder( @@ -216,18 +230,19 @@ def create_transaction_for_modifying_delegation_cap(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_setting_automatic_activation(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_setting_automatic_activation( + self, sender: Address, delegation_contract: Address + ) -> Transaction: parts = [ "setAutomaticActivation", - self.serializer.serialize([StringValue('true')]) + self.serializer.serialize([StringValue("true")]), ] transaction = TransactionBuilder( @@ -235,18 +250,19 @@ def create_transaction_for_setting_automatic_activation(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_unsetting_automatic_activation(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_unsetting_automatic_activation( + self, sender: Address, delegation_contract: Address + ) -> Transaction: parts = [ "setAutomaticActivation", - self.serializer.serialize([StringValue('false')]) + self.serializer.serialize([StringValue("false")]), ] transaction = TransactionBuilder( @@ -254,18 +270,19 @@ def create_transaction_for_unsetting_automatic_activation(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_setting_cap_check_on_redelegate_rewards(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_setting_cap_check_on_redelegate_rewards( + self, sender: Address, delegation_contract: Address + ) -> Transaction: parts = [ "setCheckCapOnReDelegateRewards", - self.serializer.serialize([StringValue('true')]) + self.serializer.serialize([StringValue("true")]), ] transaction = TransactionBuilder( @@ -273,18 +290,19 @@ def create_transaction_for_setting_cap_check_on_redelegate_rewards(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_unsetting_cap_check_on_redelegate_rewards(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_unsetting_cap_check_on_redelegate_rewards( + self, sender: Address, delegation_contract: Address + ) -> Transaction: parts = [ "setCheckCapOnReDelegateRewards", - self.serializer.serialize([StringValue('false')]) + self.serializer.serialize([StringValue("false")]), ] transaction = TransactionBuilder( @@ -292,25 +310,26 @@ def create_transaction_for_unsetting_cap_check_on_redelegate_rewards(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_setting_metadata(self, - sender: Address, - delegation_contract: Address, - name: str, - website: str, - identifier: str) -> Transaction: + def create_transaction_for_setting_metadata( + self, + sender: Address, + delegation_contract: Address, + name: str, + website: str, + identifier: str, + ) -> Transaction: parts = ["setMetaData"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(name), - StringValue(website), - StringValue(identifier) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [StringValue(name), StringValue(website), StringValue(identifier)] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -319,16 +338,16 @@ def create_transaction_for_setting_metadata(self, sender=sender, receiver=delegation_contract, data_parts=parts, - gas_limit=self.config.gas_limit_delegation_operations + self.config.additional_gas_for_delegation_operations, - add_data_movement_gas=True + gas_limit=self.config.gas_limit_delegation_operations + + self.config.additional_gas_for_delegation_operations, + add_data_movement_gas=True, ).build() return transaction - def create_transaction_for_delegating(self, - sender: Address, - delegation_contract: Address, - amount: int) -> Transaction: + def create_transaction_for_delegating( + self, sender: Address, delegation_contract: Address, amount: int + ) -> Transaction: return TransactionBuilder( config=self.config, sender=sender, @@ -336,12 +355,10 @@ def create_transaction_for_delegating(self, data_parts=["delegate"], gas_limit=12000000, add_data_movement_gas=False, - amount=amount + amount=amount, ).build() - def create_transaction_for_claiming_rewards(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_claiming_rewards(self, sender: Address, delegation_contract: Address) -> Transaction: return TransactionBuilder( config=self.config, sender=sender, @@ -349,12 +366,10 @@ def create_transaction_for_claiming_rewards(self, data_parts=["claimRewards"], gas_limit=6000000, add_data_movement_gas=False, - amount=0 + amount=0, ).build() - def create_transaction_for_redelegating_rewards(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_redelegating_rewards(self, sender: Address, delegation_contract: Address) -> Transaction: return TransactionBuilder( config=self.config, sender=sender, @@ -362,26 +377,26 @@ def create_transaction_for_redelegating_rewards(self, data_parts=["reDelegateRewards"], gas_limit=12000000, add_data_movement_gas=False, - amount=0 + amount=0, ).build() - def create_transaction_for_undelegating(self, - sender: Address, - delegation_contract: Address, - amount: int) -> Transaction: + def create_transaction_for_undelegating( + self, sender: Address, delegation_contract: Address, amount: int + ) -> Transaction: return TransactionBuilder( config=self.config, sender=sender, receiver=delegation_contract, - data_parts=["unDelegate", self.serializer.serialize([BigUIntValue(amount)])], + data_parts=[ + "unDelegate", + self.serializer.serialize([BigUIntValue(amount)]), + ], gas_limit=12000000, add_data_movement_gas=False, - amount=0 + amount=0, ).build() - def create_transaction_for_withdrawing(self, - sender: Address, - delegation_contract: Address) -> Transaction: + def create_transaction_for_withdrawing(self, sender: Address, delegation_contract: Address) -> Transaction: return TransactionBuilder( config=self.config, sender=sender, @@ -389,5 +404,5 @@ def create_transaction_for_withdrawing(self, data_parts=["withdraw"], gas_limit=12000000, add_data_movement_gas=False, - amount=0 + amount=0, ).build() diff --git a/multiversx_sdk/delegation/delegation_transactions_factory_test.py b/multiversx_sdk/delegation/delegation_transactions_factory_test.py index b4db9d79..d1b22aa0 100644 --- a/multiversx_sdk/delegation/delegation_transactions_factory_test.py +++ b/multiversx_sdk/delegation/delegation_transactions_factory_test.py @@ -2,7 +2,6 @@ from multiversx_sdk.core.constants import DELEGATION_MANAGER_SC_ADDRESS_HEX from multiversx_sdk.delegation import DelegationTransactionsFactory from multiversx_sdk.wallet import ValidatorSecretKey, ValidatorSigner - from multiversx_sdk.wallet.validator_keys import ValidatorPublicKey @@ -15,7 +14,7 @@ def test_create_transaction_for_new_delegation_contract(self): sender=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), total_delegation_cap=5000000000000000000000, service_fee=10, - amount=1250000000000000000000 + amount=1250000000000000000000, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -30,7 +29,8 @@ def test_create_transaction_for_adding_nodes(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") validator_secret_key = ValidatorSecretKey.from_string( - "7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247") + "7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247" + ) validator_signer = ValidatorSigner(validator_secret_key) signed_message = validator_signer.sign(bytes.fromhex(delegation_contract.to_hex())) @@ -43,13 +43,16 @@ def test_create_transaction_for_adding_nodes(self): sender=sender, delegation_contract=delegation_contract, public_keys=public_keys, - signed_messages=signed_messages + signed_messages=signed_messages, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "addNodes@e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208@81109fa1c8d3dc7b6c2d6e65206cc0bc1a83c9b2d1eb91a601d66ad32def430827d5eb52917bd2b0d04ce195738db216" + assert ( + transaction.data.decode() + == "addNodes@e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208@81109fa1c8d3dc7b6c2d6e65206cc0bc1a83c9b2d1eb91a601d66ad32def430827d5eb52917bd2b0d04ce195738db216" + ) assert transaction.value == 0 def test_create_transaction_for_removing_nodes(self): @@ -61,13 +64,16 @@ def test_create_transaction_for_removing_nodes(self): transaction = self.factory.create_transaction_for_removing_nodes( sender=sender, delegation_contract=delegation_contract, - public_keys=public_keys + public_keys=public_keys, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "removeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + assert ( + transaction.data.decode() + == "removeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) assert transaction.value == 0 def test_create_transaction_for_staking_nodes(self): @@ -79,13 +85,16 @@ def test_create_transaction_for_staking_nodes(self): transaction = self.factory.create_transaction_for_staking_nodes( sender=sender, delegation_contract=delegation_contract, - public_keys=public_keys + public_keys=public_keys, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "stakeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + assert ( + transaction.data.decode() + == "stakeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) assert transaction.value == 0 def test_create_transaction_for_unbonding_nodes(self): @@ -97,13 +106,16 @@ def test_create_transaction_for_unbonding_nodes(self): transaction = self.factory.create_transaction_for_unbonding_nodes( sender=sender, delegation_contract=delegation_contract, - public_keys=public_keys + public_keys=public_keys, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "unBondNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + assert ( + transaction.data.decode() + == "unBondNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) assert transaction.value == 0 def test_create_transaction_for_unstaking_nodes(self): @@ -115,13 +127,16 @@ def test_create_transaction_for_unstaking_nodes(self): transaction = self.factory.create_transaction_for_unstaking_nodes( sender=sender, delegation_contract=delegation_contract, - public_keys=public_keys + public_keys=public_keys, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "unStakeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + assert ( + transaction.data.decode() + == "unStakeNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) assert transaction.value == 0 def test_create_transaction_for_unjailing_nodes(self): @@ -134,13 +149,16 @@ def test_create_transaction_for_unjailing_nodes(self): sender=sender, delegation_contract=delegation_contract, public_keys=public_keys, - amount=25000000000000000000 # 2.5 egld + amount=25000000000000000000, # 2.5 egld ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc" assert transaction.data - assert transaction.data.decode() == "unJailNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + assert ( + transaction.data.decode() + == "unJailNodes@000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) assert transaction.value == 25000000000000000000 def test_create_transaction_for_changing_service_fee(self): @@ -148,9 +166,7 @@ def test_create_transaction_for_changing_service_fee(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_changing_service_fee( - sender=sender, - delegation_contract=delegation_contract, - service_fee=10 + sender=sender, delegation_contract=delegation_contract, service_fee=10 ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -166,7 +182,7 @@ def test_create_transaction_for_modifying_delegation_cap(self): transaction = self.factory.create_transaction_for_modifying_delegation_cap( sender=sender, delegation_contract=delegation_contract, - delegation_cap=5000000000000000000000 + delegation_cap=5000000000000000000000, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -180,8 +196,7 @@ def test_create_transaction_for_setting_automatic_activation(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_setting_automatic_activation( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -195,8 +210,7 @@ def test_create_transaction_for_unsetting_automatic_activation(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_unsetting_automatic_activation( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -210,8 +224,7 @@ def test_create_transaction_for_setting_cap_check_on_redelegate_rewards(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_setting_cap_check_on_redelegate_rewards( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -225,8 +238,7 @@ def test_create_transaction_for_unsetting_cap_check_on_redelegate_rewards(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_unsetting_cap_check_on_redelegate_rewards( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -244,7 +256,7 @@ def test_create_transaction_for_setting_metadata(self): delegation_contract=delegation_contract, name="name", website="website", - identifier="identifier" + identifier="identifier", ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -260,7 +272,7 @@ def test_create_transaction_for_delegating(self): transaction = self.factory.create_transaction_for_delegating( sender=sender, delegation_contract=delegation_contract, - amount=1000000000000000000 + amount=1000000000000000000, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -275,8 +287,7 @@ def test_create_transaction_for_claiming_rewards(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_claiming_rewards( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -291,8 +302,7 @@ def test_create_transaction_for_redelegating_rewards(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_redelegating_rewards( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -309,7 +319,7 @@ def test_create_transaction_for_undelegating(self): transaction = self.factory.create_transaction_for_undelegating( sender=sender, delegation_contract=delegation_contract, - amount=1000000000000000000 + amount=1000000000000000000, ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" @@ -324,8 +334,7 @@ def test_create_transaction_for_withdrawing(self): delegation_contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqtllllls002zgc") transaction = self.factory.create_transaction_for_withdrawing( - sender=sender, - delegation_contract=delegation_contract + sender=sender, delegation_contract=delegation_contract ) assert transaction.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" diff --git a/multiversx_sdk/delegation/delegation_transactions_outcome_parser.py b/multiversx_sdk/delegation/delegation_transactions_outcome_parser.py index 647d8306..d534f3b3 100644 --- a/multiversx_sdk/delegation/delegation_transactions_outcome_parser.py +++ b/multiversx_sdk/delegation/delegation_transactions_outcome_parser.py @@ -1,18 +1,23 @@ -from multiversx_sdk.core import (Address, TransactionEvent, - TransactionOnNetwork, - find_events_by_identifier) +from multiversx_sdk.core import ( + Address, + TransactionEvent, + TransactionOnNetwork, + find_events_by_identifier, +) from multiversx_sdk.core.config import LibraryConfig from multiversx_sdk.core.errors import ParseTransactionOnNetworkError -from multiversx_sdk.delegation.delegation_transactions_outcome_parser_types import \ - CreateNewDelegationContractOutcome +from multiversx_sdk.delegation.delegation_transactions_outcome_parser_types import ( + CreateNewDelegationContractOutcome, +) class DelegationTransactionsOutcomeParser: def __init__(self) -> None: pass - def parse_create_new_delegation_contract(self, - transaction: TransactionOnNetwork) -> list[CreateNewDelegationContractOutcome]: + def parse_create_new_delegation_contract( + self, transaction: TransactionOnNetwork + ) -> list[CreateNewDelegationContractOutcome]: self._ensure_no_error(transaction.logs.events) events = find_events_by_identifier(transaction, "SCDeploy") @@ -24,7 +29,9 @@ def _ensure_no_error(self, transaction_events: list[TransactionEvent]) -> None: data = event.additional_data[0].decode()[1:] if len(event.additional_data[0]) else "" message = event.topics[1].decode() - raise ParseTransactionOnNetworkError(f"encountered signalError: {message} ({bytes.fromhex(data).decode()})") + raise ParseTransactionOnNetworkError( + f"encountered signalError: {message} ({bytes.fromhex(data).decode()})" + ) def _extract_contract_address(self, event: TransactionEvent) -> Address: if not event.topics[0]: diff --git a/multiversx_sdk/delegation/delegation_transactions_outcome_parser_test.py b/multiversx_sdk/delegation/delegation_transactions_outcome_parser_test.py index bc04c59d..52f4620a 100644 --- a/multiversx_sdk/delegation/delegation_transactions_outcome_parser_test.py +++ b/multiversx_sdk/delegation/delegation_transactions_outcome_parser_test.py @@ -1,12 +1,15 @@ import base64 from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transaction_on_network import (SmartContractResult, - TransactionEvent, - TransactionLogs) +from multiversx_sdk.core.transaction_on_network import ( + SmartContractResult, + TransactionEvent, + TransactionLogs, +) from multiversx_sdk.delegation import DelegationTransactionsOutcomeParser -from multiversx_sdk.testutils.mock_transaction_on_network import \ - get_empty_transaction_on_network +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_transaction_on_network, +) from multiversx_sdk.testutils.utils import base64_topics_to_bytes @@ -30,7 +33,7 @@ def test_parse_create_new_delegation_contract(self): identifier="delegate", topics=base64_topics_to_bytes(encodedTopics), data=b"", - additional_data=[] + additional_data=[], ) encodedTopics = [ @@ -44,7 +47,7 @@ def test_parse_create_new_delegation_contract(self): identifier="SCDeploy", topics=base64_topics_to_bytes(encodedTopics), data=b"", - additional_data=[] + additional_data=[], ) logs = TransactionLogs(address=Address.empty(), events=[delegate_event, sc_deploy_event]) @@ -56,12 +59,12 @@ def test_parse_create_new_delegation_contract(self): identifier="completedTxEvent", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) sc_result_log = TransactionLogs( address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), - events=[sc_result_event] + events=[sc_result_event], ) sc_result = SmartContractResult( @@ -69,8 +72,9 @@ def test_parse_create_new_delegation_contract(self): sender=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqylllslmq6y6"), receiver=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), data=base64.b64decode( - "QDZmNmJAMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxMGZmZmZmZg=="), - logs=sc_result_log + "QDZmNmJAMDAwMDAwMDAwMDAwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxMGZmZmZmZg==" + ), + logs=sc_result_log, ) tx = get_empty_transaction_on_network() diff --git a/multiversx_sdk/entrypoints/__init__.py b/multiversx_sdk/entrypoints/__init__.py index 22440f34..561ef428 100644 --- a/multiversx_sdk/entrypoints/__init__.py +++ b/multiversx_sdk/entrypoints/__init__.py @@ -1,9 +1,15 @@ from multiversx_sdk.entrypoints.entrypoints import ( DevnetEntrypoint, + LocalnetEntrypoint, MainnetEntrypoint, NetworkEntrypoint, TestnetEntrypoint, - LocalnetEntrypoint, ) -__all__ = ["DevnetEntrypoint", "MainnetEntrypoint", "NetworkEntrypoint", "TestnetEntrypoint", "LocalnetEntrypoint"] +__all__ = [ + "DevnetEntrypoint", + "MainnetEntrypoint", + "NetworkEntrypoint", + "TestnetEntrypoint", + "LocalnetEntrypoint", +] diff --git a/multiversx_sdk/entrypoints/entrypoints.py b/multiversx_sdk/entrypoints/entrypoints.py index fdac128c..e965fd5f 100644 --- a/multiversx_sdk/entrypoints/entrypoints.py +++ b/multiversx_sdk/entrypoints/entrypoints.py @@ -2,7 +2,9 @@ from multiversx_sdk.abi.abi import Abi from multiversx_sdk.account_management import AccountController -from multiversx_sdk.account_management.account_transactions_factory import AccountTransactionsFactory +from multiversx_sdk.account_management.account_transactions_factory import ( + AccountTransactionsFactory, +) from multiversx_sdk.accounts.account import Account from multiversx_sdk.core import ( Address, @@ -14,22 +16,36 @@ ) from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.delegation import DelegationController -from multiversx_sdk.delegation.delegation_transactions_factory import DelegationTransactionsFactory +from multiversx_sdk.delegation.delegation_transactions_factory import ( + DelegationTransactionsFactory, +) from multiversx_sdk.entrypoints.config import ( DevnetEntrypointConfig, + LocalnetEntrypointConfig, MainnetEntrypointConfig, TestnetEntrypointConfig, - LocalnetEntrypointConfig, ) from multiversx_sdk.entrypoints.errors import InvalidNetworkProviderKindError from multiversx_sdk.network_providers import ApiNetworkProvider, ProxyNetworkProvider from multiversx_sdk.relayed.relayed_controller import RelayedController -from multiversx_sdk.relayed.relayed_transactions_factory import RelayedTransactionsFactory -from multiversx_sdk.smart_contracts.smart_contract_controller import SmartContractController -from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import SmartContractTransactionsFactory -from multiversx_sdk.token_management.token_management_controller import TokenManagementController -from multiversx_sdk.token_management.token_management_transactions_factory import TokenManagementTransactionsFactory -from multiversx_sdk.transfers.transfer_transactions_factory import TransferTransactionsFactory +from multiversx_sdk.relayed.relayed_transactions_factory import ( + RelayedTransactionsFactory, +) +from multiversx_sdk.smart_contracts.smart_contract_controller import ( + SmartContractController, +) +from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import ( + SmartContractTransactionsFactory, +) +from multiversx_sdk.token_management.token_management_controller import ( + TokenManagementController, +) +from multiversx_sdk.token_management.token_management_transactions_factory import ( + TokenManagementTransactionsFactory, +) +from multiversx_sdk.transfers.transfer_transactions_factory import ( + TransferTransactionsFactory, +) from multiversx_sdk.transfers.transfers_controller import TransfersController from multiversx_sdk.wallet.user_keys import UserSecretKey from multiversx_sdk.wallet.user_verifer import UserVerifier @@ -60,7 +76,8 @@ def verify_transaction_signature(self, transaction: Transaction) -> bool: tx_computer = TransactionComputer() return verifier.verify( - data=tx_computer.compute_bytes_for_verifying(transaction), signature=transaction.signature + data=tx_computer.compute_bytes_for_verifying(transaction), + signature=transaction.signature, ) def verify_message_signature(self, message: Message) -> bool: @@ -70,7 +87,10 @@ def verify_message_signature(self, message: Message) -> bool: verifier = UserVerifier.from_address(message.address) message_computer = MessageComputer() - return verifier.verify(data=message_computer.compute_bytes_for_verifying(message), signature=message.signature) + return verifier.verify( + data=message_computer.compute_bytes_for_verifying(message), + signature=message.signature, + ) def recall_account_nonce(self, address: Address) -> int: return self.network_provider.get_account(address).nonce @@ -96,7 +116,9 @@ def await_transaction_completed(self, tx_hash: Union[str, bytes]) -> Transaction def get_transaction(self, tx_hash: Union[str, bytes]) -> TransactionOnNetwork: return self.network_provider.get_transaction(tx_hash) - def create_network_provider(self) -> Union[ApiNetworkProvider, ProxyNetworkProvider]: + def create_network_provider( + self, + ) -> Union[ApiNetworkProvider, ProxyNetworkProvider]: return self.network_provider def create_delegation_controller(self) -> DelegationController: @@ -126,7 +148,9 @@ def create_smart_contract_transactions_factory(self, abi: Optional[Abi] = None) def create_token_management_controller(self) -> TokenManagementController: return TokenManagementController(self.chain_id, self.network_provider) - def create_token_management_transactions_factory(self) -> TokenManagementTransactionsFactory: + def create_token_management_transactions_factory( + self, + ) -> TokenManagementTransactionsFactory: return TokenManagementTransactionsFactory(TransactionsFactoryConfig(self.chain_id)) def create_transfers_controller(self) -> TransfersController: diff --git a/multiversx_sdk/entrypoints/entrypoints_test.py b/multiversx_sdk/entrypoints/entrypoints_test.py index 7aaac10b..7d283eea 100644 --- a/multiversx_sdk/entrypoints/entrypoints_test.py +++ b/multiversx_sdk/entrypoints/entrypoints_test.py @@ -148,7 +148,9 @@ def test_version_and_options_are_correct(self): account.nonce = self.entrypoint.recall_account_nonce(account.address) transaction = controller.create_transaction_for_saving_key_value( - sender=account, nonce=account.nonce, key_value_pairs={b"testKey": b"testValue"} + sender=account, + nonce=account.nonce, + key_value_pairs={b"testKey": b"testValue"}, ) assert transaction.version == 2 diff --git a/multiversx_sdk/network_providers/__init__.py b/multiversx_sdk/network_providers/__init__.py index a429d0b8..a329fa06 100644 --- a/multiversx_sdk/network_providers/__init__.py +++ b/multiversx_sdk/network_providers/__init__.py @@ -1,26 +1,49 @@ from multiversx_sdk.network_providers.account_awaiter import AccountAwaiter -from multiversx_sdk.network_providers.api_network_provider import \ - ApiNetworkProvider +from multiversx_sdk.network_providers.api_network_provider import ApiNetworkProvider from multiversx_sdk.network_providers.config import NetworkProviderConfig from multiversx_sdk.network_providers.errors import GenericError -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider from multiversx_sdk.network_providers.resources import ( - AccountOnNetwork, AccountStorage, AccountStorageEntry, AwaitingOptions, - BlockCoordinates, BlockOnNetwork, FungibleTokenMetadata, GenericResponse, - NetworkConfig, NetworkStatus, TokenAmountOnNetwork, - TokensCollectionMetadata, TransactionCostResponse) -from multiversx_sdk.network_providers.transaction_awaiter import \ - TransactionAwaiter + AccountOnNetwork, + AccountStorage, + AccountStorageEntry, + AwaitingOptions, + BlockCoordinates, + BlockOnNetwork, + FungibleTokenMetadata, + GenericResponse, + NetworkConfig, + NetworkStatus, + TokenAmountOnNetwork, + TokensCollectionMetadata, + TransactionCostResponse, +) +from multiversx_sdk.network_providers.transaction_awaiter import TransactionAwaiter from multiversx_sdk.network_providers.transaction_decoder import ( - TransactionDecoder, TransactionMetadata) + TransactionDecoder, + TransactionMetadata, +) __all__ = [ - "GenericError", "GenericResponse", "ApiNetworkProvider", - "ProxyNetworkProvider", "TransactionAwaiter", - "TransactionDecoder", "TransactionMetadata", "NetworkProviderConfig", - "AccountOnNetwork", "AccountStorage", "AccountStorageEntry", "AwaitingOptions", - "BlockCoordinates", "BlockOnNetwork", "FungibleTokenMetadata", - "NetworkConfig", "NetworkStatus", "TokenAmountOnNetwork", - "TokensCollectionMetadata", "TransactionCostResponse", "AccountAwaiter" + "GenericError", + "GenericResponse", + "ApiNetworkProvider", + "ProxyNetworkProvider", + "TransactionAwaiter", + "TransactionDecoder", + "TransactionMetadata", + "NetworkProviderConfig", + "AccountOnNetwork", + "AccountStorage", + "AccountStorageEntry", + "AwaitingOptions", + "BlockCoordinates", + "BlockOnNetwork", + "FungibleTokenMetadata", + "NetworkConfig", + "NetworkStatus", + "TokenAmountOnNetwork", + "TokensCollectionMetadata", + "TransactionCostResponse", + "AccountAwaiter", ] diff --git a/multiversx_sdk/network_providers/account_awaiter.py b/multiversx_sdk/network_providers/account_awaiter.py index 259808f5..bf5ce3e8 100644 --- a/multiversx_sdk/network_providers/account_awaiter.py +++ b/multiversx_sdk/network_providers/account_awaiter.py @@ -6,9 +6,11 @@ from multiversx_sdk.network_providers.constants import ( DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS, DEFAULT_ACCOUNT_AWAITING_POLLING_TIMEOUT_IN_MILLISECONDS, - DEFAULT_ACCOUNT_AWAITING_TIMEOUT_IN_MILLISECONDS) -from multiversx_sdk.network_providers.errors import \ - ExpectedAccountConditionNotReachedError + DEFAULT_ACCOUNT_AWAITING_TIMEOUT_IN_MILLISECONDS, +) +from multiversx_sdk.network_providers.errors import ( + ExpectedAccountConditionNotReachedError, +) from multiversx_sdk.network_providers.resources import AccountOnNetwork ONE_SECOND_IN_MILLISECONDS = 1000 @@ -17,18 +19,19 @@ class IAccountFetcher(Protocol): - def get_account(self, address: Address) -> AccountOnNetwork: - ... + def get_account(self, address: Address) -> AccountOnNetwork: ... class AccountAwaiter: """AccountAwaiter allows one to await until a specific event occurs on a given address.""" - def __init__(self, - fetcher: IAccountFetcher, - polling_interval_in_milliseconds: Optional[int] = None, - timeout_interval_in_milliseconds: Optional[int] = None, - patience_time_in_milliseconds: Optional[int] = None) -> None: + def __init__( + self, + fetcher: IAccountFetcher, + polling_interval_in_milliseconds: Optional[int] = None, + timeout_interval_in_milliseconds: Optional[int] = None, + patience_time_in_milliseconds: Optional[int] = None, + ) -> None: """ Args: fetcher (IAccountFetcher): Used to fetch the account of the network. @@ -55,19 +58,22 @@ def __init__(self, def await_on_condition(self, address: Address, condition: Callable[[AccountOnNetwork], bool]) -> AccountOnNetwork: """Waits until the condition is satisfied.""" + def do_fetch(): return self.fetcher.get_account(address) return self._await_conditionally( is_satisfied=condition, do_fetch=do_fetch, - error=ExpectedAccountConditionNotReachedError() + error=ExpectedAccountConditionNotReachedError(), ) - def _await_conditionally(self, - is_satisfied: Callable[[AccountOnNetwork], bool], - do_fetch: Callable[[], AccountOnNetwork], - error: Exception) -> AccountOnNetwork: + def _await_conditionally( + self, + is_satisfied: Callable[[AccountOnNetwork], bool], + do_fetch: Callable[[], AccountOnNetwork], + error: Exception, + ) -> AccountOnNetwork: is_condition_satisfied = False fetched_data: Union[AccountOnNetwork, None] = None max_number_of_retries = self.timeout_interval_in_milliseconds // self.polling_interval_in_milliseconds diff --git a/multiversx_sdk/network_providers/account_awaiter_test.py b/multiversx_sdk/network_providers/account_awaiter_test.py index 7985825c..d9479adc 100644 --- a/multiversx_sdk/network_providers/account_awaiter_test.py +++ b/multiversx_sdk/network_providers/account_awaiter_test.py @@ -4,11 +4,13 @@ from multiversx_sdk.core.transaction import Transaction from multiversx_sdk.core.transaction_computer import TransactionComputer from multiversx_sdk.network_providers.account_awaiter import AccountAwaiter -from multiversx_sdk.network_providers.api_network_provider import \ - ApiNetworkProvider +from multiversx_sdk.network_providers.api_network_provider import ApiNetworkProvider from multiversx_sdk.network_providers.resources import AccountOnNetwork from multiversx_sdk.testutils.mock_network_provider import ( - MockNetworkProvider, TimelinePointMarkCompleted, TimelinePointWait) + MockNetworkProvider, + TimelinePointMarkCompleted, + TimelinePointWait, +) from multiversx_sdk.testutils.utils import create_account_egld_balance from multiversx_sdk.testutils.wallets import load_wallets @@ -19,7 +21,7 @@ class TestAccountAwaiter: fetcher=provider, polling_interval_in_milliseconds=42, timeout_interval_in_milliseconds=42 * 42, - patience_time_in_milliseconds=0 + patience_time_in_milliseconds=0, ) def test_await_on_balance_increase(self): @@ -30,7 +32,12 @@ def test_await_on_balance_increase(self): # adds 7 EGLD to the account balance self.provider.mock_account_balance_timeline_by_address( alice, - [TimelinePointWait(40), TimelinePointWait(40), TimelinePointWait(45), TimelinePointMarkCompleted()] + [ + TimelinePointWait(40), + TimelinePointWait(40), + TimelinePointWait(45), + TimelinePointMarkCompleted(), + ], ) def condition(account: AccountOnNetwork): @@ -55,7 +62,7 @@ def test_await_for_account_balance_increase_on_network(self): receiver=frank, gas_limit=50000, chain_id="D", - value=value + value=value, ) transaction.nonce = api.get_account(alice_address).nonce transaction.signature = alice.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) diff --git a/multiversx_sdk/network_providers/api_network_provider.py b/multiversx_sdk/network_providers/api_network_provider.py index add10d90..3a34b751 100644 --- a/multiversx_sdk/network_providers/api_network_provider.py +++ b/multiversx_sdk/network_providers/api_network_provider.py @@ -3,7 +3,13 @@ import requests -from multiversx_sdk.core import Address, Token, TokenComputer, Transaction, TransactionOnNetwork +from multiversx_sdk.core import ( + Address, + Token, + TokenComputer, + Transaction, + TransactionOnNetwork, +) from multiversx_sdk.core.config import LibraryConfig from multiversx_sdk.core.constants import METACHAIN_ID from multiversx_sdk.network_providers.account_awaiter import AccountAwaiter @@ -12,7 +18,10 @@ BASE_USER_AGENT, DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS, ) -from multiversx_sdk.network_providers.errors import GenericError, TransactionFetchingError +from multiversx_sdk.network_providers.errors import ( + GenericError, + TransactionFetchingError, +) from multiversx_sdk.network_providers.http_resources import ( account_from_api_response, account_storage_entry_from_response, @@ -104,9 +113,7 @@ def get_account_storage(self, address: Address) -> AccountStorage: def get_account_storage_entry(self, address: Address, entry_key: str) -> AccountStorageEntry: """Fetches a specific storage entry of an account.""" key_as_hex = entry_key.encode().hex() - response: dict[str, Any] = self.do_get_generic( - f"address/{address.to_bech32()}/key/{key_as_hex}" - ) + response: dict[str, Any] = self.do_get_generic(f"address/{address.to_bech32()}/key/{key_as_hex}") return account_storage_entry_from_response(response.get("data", {}), entry_key) def await_account_on_condition( @@ -117,9 +124,7 @@ def await_account_on_condition( ) -> AccountOnNetwork: """Waits until an account satisfies a given condition.""" if options is None: - options = AwaitingOptions( - patience_in_milliseconds=DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS - ) + options = AwaitingOptions(patience_in_milliseconds=DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS) awaiter = AccountAwaiter( fetcher=self, @@ -135,9 +140,7 @@ def send_transaction(self, transaction: Transaction) -> bytes: response = self.do_post_generic("transactions", transaction.to_dictionary()) return bytes.fromhex(response.get("txHash", "")) - def simulate_transaction( - self, transaction: Transaction, check_signature: bool = False - ) -> TransactionOnNetwork: + def simulate_transaction(self, transaction: Transaction, check_signature: bool = False) -> TransactionOnNetwork: """Simulates a transaction.""" url = "transaction/simulate?checkSignature=false" @@ -145,15 +148,11 @@ def simulate_transaction( url = "transaction/simulate" response: dict[str, Any] = self.do_post_generic(url, transaction.to_dictionary()) - return transaction_from_simulate_response( - transaction, 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.""" - response: dict[str, Any] = self.do_post_generic( - "transaction/cost", transaction.to_dictionary() - ) + response: dict[str, Any] = self.do_post_generic("transaction/cost", transaction.to_dictionary()) return transaction_cost_estimation_from_response(response.get("data", {})) def send_transactions(self, transactions: list[Transaction]) -> tuple[int, list[bytes]]: @@ -163,9 +162,7 @@ def send_transactions(self, transactions: list[Transaction]) -> tuple[int, list[ If a transaction is not accepted, its hash is empty in the returned list. """ transactions_as_dictionaries = [transaction.to_dictionary() for transaction in transactions] - response: dict[str, Any] = self.do_post_generic( - "transaction/send-multiple", transactions_as_dictionaries - ) + response: dict[str, Any] = self.do_post_generic("transaction/send-multiple", transactions_as_dictionaries) return transactions_from_send_multiple_response(response.get("data", {}), len(transactions)) def get_transaction(self, transaction_hash: Union[str, bytes]) -> TransactionOnNetwork: @@ -178,7 +175,9 @@ def get_transaction(self, transaction_hash: Union[str, bytes]) -> TransactionOnN return transaction_from_api_response(transaction_hash, response) def await_transaction_completed( - self, transaction_hash: Union[str, bytes], options: Optional[AwaitingOptions] = None + self, + transaction_hash: Union[str, bytes], + options: Optional[AwaitingOptions] = None, ) -> TransactionOnNetwork: """Waits until the transaction is completely processed.""" transaction_hash = convert_tx_hash_to_string(transaction_hash) @@ -225,9 +224,7 @@ def get_token_of_account(self, address: Address, token: Token) -> TokenAmountOnN identifier = TokenComputer().compute_extended_identifier(token) result = self.do_get_generic(f"accounts/{address.to_bech32()}/nfts/{identifier}") else: - result = self.do_get_generic( - f"accounts/{address.to_bech32()}/tokens/{token.identifier}" - ) + result = self.do_get_generic(f"accounts/{address.to_bech32()}/tokens/{token.identifier}") return token_amount_from_api_response(result) @@ -273,9 +270,7 @@ def do_get_generic(self, url: str, url_parameters: Optional[dict[str, Any]] = No response = self._do_get(url) return response - def do_post_generic( - self, url: str, data: Any, url_parameters: Optional[dict[str, Any]] = None - ) -> Any: + def do_post_generic(self, url: str, data: Any, url_parameters: Optional[dict[str, Any]] = None) -> Any: """Does a generic GET request against the network(handles API enveloping).""" url = f"{self.url}/{url}" diff --git a/multiversx_sdk/network_providers/api_network_provider_test.py b/multiversx_sdk/network_providers/api_network_provider_test.py index 3d01bff1..9dc90078 100644 --- a/multiversx_sdk/network_providers/api_network_provider_test.py +++ b/multiversx_sdk/network_providers/api_network_provider_test.py @@ -1,23 +1,25 @@ import pytest import requests -from multiversx_sdk.core import (Address, Token, Transaction, - TransactionComputer, TransactionOnNetwork, - TransactionStatus) -from multiversx_sdk.network_providers.api_network_provider import \ - ApiNetworkProvider +from multiversx_sdk.core import ( + Address, + Token, + Transaction, + TransactionComputer, + TransactionOnNetwork, + TransactionStatus, +) +from multiversx_sdk.network_providers.api_network_provider import ApiNetworkProvider from multiversx_sdk.network_providers.config import NetworkProviderConfig -from multiversx_sdk.network_providers.http_resources import \ - account_from_api_response +from multiversx_sdk.network_providers.http_resources import account_from_api_response from multiversx_sdk.network_providers.resources import TokenAmountOnNetwork -from multiversx_sdk.smart_contracts.smart_contract_query import \ - SmartContractQuery +from multiversx_sdk.smart_contracts.smart_contract_query import SmartContractQuery from multiversx_sdk.testutils.wallets import load_wallets @pytest.mark.networkInteraction class TestApi: - api = ApiNetworkProvider('https://devnet-api.multiversx.com') + api = ApiNetworkProvider("https://devnet-api.multiversx.com") def test_get_network_config(self): result = self.api.get_network_config() @@ -40,7 +42,7 @@ def test_get_network_status(self): assert result.raw def test_get_block(self): - block_hash=bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") + block_hash = bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") result_by_hash = self.api.get_block(block_hash) assert result_by_hash.hash == bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") @@ -53,24 +55,21 @@ def test_get_latest_block(self): assert result def test_get_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") result = self.api.get_account(address) assert result.address.to_bech32() == "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" assert not result.username assert result.contract_owner_address is None - address = Address.new_from_bech32( - "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" - ) + address = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen") result = self.api.get_account(address) assert result.address.to_bech32() == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" assert not result.username assert result.contract_owner_address == Address.new_from_bech32( - "erd1wzx0tak22f2me4g7wpxfae2w3htfue7khrg28fy6wu8x9hzq05vqm8qhnm") + "erd1wzx0tak22f2me4g7wpxfae2w3htfue7khrg28fy6wu8x9hzq05vqm8qhnm" + ) assert result.is_contract_payable is False assert result.is_contract_readable @@ -101,11 +100,9 @@ def test_send_transaction(self): version=2, signature=bytes.fromhex( "faf50b8368cb2c20597dad671a14aa76d4c65937d6e522c64946f16ad6a250262463e444596fa7ee2af1273f6ad0329d43af48d1ae5f3b295bc8f48fdba41a05" - ) - ) - expected_hash = ( - bytes.fromhex("fc914860c1d137ed8baa602e561381f97c7bad80d150c5bf90760d3cfd3a4cea") + ), ) + expected_hash = bytes.fromhex("fc914860c1d137ed8baa602e561381f97c7bad80d150c5bf90760d3cfd3a4cea") assert self.api.send_transaction(transaction) == expected_hash @@ -121,7 +118,7 @@ def test_send_transaction_with_data(self): data=b"foo", signature=bytes.fromhex( "7a8bd08351bac6b1113545f5a896cb0b63806abd93d639bc4d16bfbc82c7b514f68ed7b36c743f4c3d2d1e1d3cb356824041d51dfe587a149f6fc9ab0dd9c408" - ) + ), ) expected_hash = "4dc7d4e18c0cf9ca7f17677ef0ac3d1363528e892996b518bee909bb17cf7929" assert self.api.send_transaction(transaction) == bytes.fromhex(expected_hash) @@ -137,7 +134,7 @@ def test_send_transactions(self): version=2, signature=bytes.fromhex( "498d5abb9f8eb69cc75f24320e8929dadbfa855ffac220d5e92175a83be68e0437801af3a1411e3d839738230097a1c38da5c8c4df3f345defc5d40300675900" - ) + ), ) invalid_tx = Transaction( @@ -145,7 +142,7 @@ def test_send_transactions(self): receiver=Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl"), gas_limit=50000, chain_id="D", - nonce=77 + nonce=77, ) last_tx = Transaction( @@ -158,7 +155,7 @@ def test_send_transactions(self): version=2, signature=bytes.fromhex( "341a2f3b738fbd20692e3bbd1cb36cb5f4ce9c0a9acc0cf4322269c0fcf34fd6bb59cd94062a9a4730e47f41b1ef3e29b69c6ab2a2a4dca9c9a7724681bc1708" - ) + ), ) transactions = [first_tx, invalid_tx, last_tx] @@ -182,7 +179,7 @@ def test_simulate_transaction(self): receiver=Address.new_from_bech32(bob.label), gas_limit=50000, chain_id="D", - signature=bytes.fromhex("".join(["0"] * 128)) + signature=bytes.fromhex("".join(["0"] * 128)), ) nonce = self.api.get_account(Address.new_from_bech32(bob.label)).nonce transaction.nonce = nonce @@ -202,14 +199,16 @@ def test_simulate_transaction(self): chain_id="D", data=b"add@07", nonce=nonce, - signature=bytes.fromhex("".join(["0"] * 128)) + signature=bytes.fromhex("".join(["0"] * 128)), ) tx_on_network = self.api.simulate_transaction(transaction) assert tx_on_network.status == TransactionStatus("success") 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].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" @@ -219,8 +218,10 @@ def test_simulate_transaction(self): assert tx_on_network.status == TransactionStatus("success") 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].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" @@ -233,7 +234,7 @@ def test_estimate_transaction_cost(self): receiver=Address.new_from_bech32(bob.label), gas_limit=50000, chain_id="D", - data="test transaction".encode() + data="test transaction".encode(), ) transaction.nonce = self.api.get_account(Address.new_from_bech32(bob.label)).nonce transaction.signature = bob.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) @@ -243,13 +244,13 @@ def test_estimate_transaction_cost(self): assert result.gas_limit == 74_000 def test_get_transaction(self): - result = self.api.get_transaction('9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c') + result = self.api.get_transaction("9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c") - assert result.hash.hex() == '9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c' + assert result.hash.hex() == "9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c" assert result.nonce == 0 assert result.status.is_completed - assert result.sender.to_bech32() == 'erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2' - assert result.receiver.to_bech32() == 'erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl' + assert result.sender.to_bech32() == "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2" + assert result.receiver.to_bech32() == "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" assert result.value == 5000000000000000000 assert result.status.status == "success" @@ -264,11 +265,14 @@ def test_get_transaction_with_events(self): assert transaction.logs.events[0].topics[2].hex() == "63616e4368616e67654f776e6572" def test_get_sc_invoking_tx(self): - result = self.api.get_transaction('6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb') + result = self.api.get_transaction("6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb") 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' + assert ( + result.data.decode() + == "issue@54455354546f6b656e@54455354@016345785d8a0000@06@63616e4368616e67654f776e6572@74727565@63616e55706772616465@74727565@63616e4164645370656369616c526f6c6573@74727565" + ) def test_query_contract(self): query = SmartContractQuery( @@ -304,16 +308,14 @@ def test_send_and_await_for_completed_transaction(self): receiver=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhdqz9j3zgpl8fg2z0jzx9n605gwxx4djd8ssruw094"), gas_limit=5000000, chain_id="D", - data="dummy@05".encode() + data="dummy@05".encode(), ) transaction.nonce = nonce + 1 transaction.signature = bob.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) hash = self.api.send_transaction(transaction) - tx_on_network = self.api.await_transaction_completed( - transaction_hash=hash - ) + tx_on_network = self.api.await_transaction_completed(transaction_hash=hash) assert not tx_on_network.status.is_successful def test_send_and_await_transaction_on_condition(self): @@ -342,7 +344,7 @@ def test_send_and_await_transaction_on_condition(self): receiver=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhdqz9j3zgpl8fg2z0jzx9n605gwxx4djd8ssruw094"), gas_limit=5000000, chain_id="D", - data="dummy@05".encode() + data="dummy@05".encode(), ) transaction.nonce = nonce + 1 transaction.signature = alice.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) @@ -352,33 +354,24 @@ def condition(tx: TransactionOnNetwork) -> bool: hash = self.api.send_transaction(transaction) - tx_on_network = self.api.await_transaction_on_condition( - transaction_hash=hash, - condition=condition - ) + tx_on_network = self.api.await_transaction_on_condition(transaction_hash=hash, condition=condition) assert tx_on_network.status.status == "fail" def test_get_token_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") result = self.api.get_token_of_account(address, Token("TEST-ff155e")) assert result.token.identifier == "TEST-ff155e" assert result.amount == 99999999999980000 - result = self.api.get_token_of_account( - address, Token("NFTEST-ec88b8", 1) - ) + result = self.api.get_token_of_account(address, Token("NFTEST-ec88b8", 1)) assert result.amount == 1 assert result.token.nonce == 1 assert result.token.identifier == "NFTEST-ec88b8-01" def test_get_fungible_tokens_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") tokens = self.api.get_fungible_tokens_of_account(address) assert len(tokens) @@ -388,9 +381,7 @@ def test_get_fungible_tokens_of_account(self): assert filtered[0].amount == 99999999999980000 def test_get_non_fungible_tokens_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") tokens = self.api.get_non_fungible_tokens_of_account(address) assert len(tokens) @@ -416,12 +407,11 @@ def test_get_definition_of_token_collection(self): assert result.decimals == 0 def test_do_get_generic(self): - query_params = { - "withGuardianInfo": "true" - } + query_params = {"withGuardianInfo": "true"} result = self.api.do_get_generic( - "accounts/erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl", query_params + "accounts/erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl", + query_params, ) account = account_from_api_response(result) guarded = bool(account.raw["isGuarded"]) @@ -435,7 +425,7 @@ def test_user_agent(self): # using the new instantiated provider with user agent config = NetworkProviderConfig(client_name="test-client") - api = ApiNetworkProvider(url='https://devnet-api.multiversx.com', config=config) + api = ApiNetworkProvider(url="https://devnet-api.multiversx.com", config=config) response = requests.get(api.url + "/network/config", **api.config.requests_options) headers = response.request.headers diff --git a/multiversx_sdk/network_providers/config.py b/multiversx_sdk/network_providers/config.py index 453d2332..21c5b132 100644 --- a/multiversx_sdk/network_providers/config.py +++ b/multiversx_sdk/network_providers/config.py @@ -2,9 +2,11 @@ class NetworkProviderConfig: - def __init__(self, - client_name: Optional[str] = None, - requests_options: Optional[dict[str, Any]] = None) -> None: + def __init__( + self, + client_name: Optional[str] = None, + requests_options: Optional[dict[str, Any]] = None, + ) -> None: self.client_name = client_name self.requests_options = requests_options or {} self.requests_options.setdefault("timeout", 5) diff --git a/multiversx_sdk/network_providers/http_resources.py b/multiversx_sdk/network_providers/http_resources.py index 3d620b0e..ae8b4e1c 100644 --- a/multiversx_sdk/network_providers/http_resources.py +++ b/multiversx_sdk/network_providers/http_resources.py @@ -5,25 +5,40 @@ from multiversx_sdk.core.code_metadata import CodeMetadata from multiversx_sdk.core.tokens import Token from multiversx_sdk.core.transaction import Transaction -from multiversx_sdk.core.transaction_on_network import (SmartContractResult, - TransactionEvent, - TransactionLogs, - TransactionOnNetwork) +from multiversx_sdk.core.transaction_on_network import ( + SmartContractResult, + TransactionEvent, + TransactionLogs, + TransactionOnNetwork, +) from multiversx_sdk.core.transaction_status import TransactionStatus from multiversx_sdk.network_providers.resources import ( - AccountOnNetwork, AccountStorage, AccountStorageEntry, BlockCoordinates, - BlockOnNetwork, FungibleTokenMetadata, NetworkConfig, NetworkStatus, - TokenAmountOnNetwork, TokensCollectionMetadata, TransactionCostResponse) + AccountOnNetwork, + AccountStorage, + AccountStorageEntry, + BlockCoordinates, + BlockOnNetwork, + FungibleTokenMetadata, + NetworkConfig, + NetworkStatus, + TokenAmountOnNetwork, + TokensCollectionMetadata, + TransactionCostResponse, +) from multiversx_sdk.smart_contracts.smart_contract_query import ( - SmartContractQuery, SmartContractQueryResponse) + SmartContractQuery, + SmartContractQueryResponse, +) -def smart_contract_query_to_vm_query_request(query: SmartContractQuery) -> dict[str, Any]: +def smart_contract_query_to_vm_query_request( + query: SmartContractQuery, +) -> dict[str, Any]: request: dict[str, Any] = { "scAddress": query.contract.to_bech32(), "funcName": query.function, "value": str(query.value if query.value else 0), - "args": [arg.hex() for arg in query.arguments] + "args": [arg.hex() for arg in query.arguments], } if query.caller: @@ -33,8 +48,8 @@ def smart_contract_query_to_vm_query_request(query: SmartContractQuery) -> dict[ def vm_query_response_to_smart_contract_query_response( - raw_response: dict[str, Any], - function: str) -> SmartContractQueryResponse: + raw_response: dict[str, Any], function: str +) -> SmartContractQueryResponse: return_data = raw_response.get("returnData", []) or raw_response.get("ReturnData", []) return_code = raw_response.get("returnCode", "") or raw_response.get("ReturnCode", "") return_message = raw_response.get("returnMessage", "") or raw_response.get("ReturnMessage", "") @@ -43,7 +58,7 @@ def vm_query_response_to_smart_contract_query_response( function=function, return_code=return_code, return_message=return_message, - return_data_parts=[base64.b64decode(item) for item in return_data] + return_data_parts=[base64.b64decode(item) for item in return_data], ) @@ -96,12 +111,14 @@ def transaction_from_api_response(tx_hash: str, response: dict[str, Any]) -> Tra signature=signature, status=status, smart_contract_results=smart_contract_results, - logs=logs + logs=logs, ) def transaction_from_proxy_response( - tx_hash: str, response: dict[str, Any], process_status: Optional[TransactionStatus] = None + tx_hash: str, + response: dict[str, Any], + process_status: Optional[TransactionStatus] = None, ) -> "TransactionOnNetwork": sender = Address.new_from_bech32(response.get("sender", "")) receiver = Address.new_from_bech32(response.get("receiver", "")) @@ -154,7 +171,7 @@ def transaction_from_proxy_response( signature=signature, status=status, smart_contract_results=smart_contract_results, - logs=logs + logs=logs, ) @@ -164,10 +181,7 @@ def transaction_logs_from_response(raw_response: dict[str, Any]) -> TransactionL events = raw_response.get("events", []) events = [transaction_events_from_response(event) for event in events] - return TransactionLogs( - address=address, - events=events - ) + return TransactionLogs(address=address, events=events) def _convert_bech32_to_address(address: str) -> Address: @@ -196,8 +210,9 @@ def transaction_events_from_response(raw_response: dict[str, Any]) -> Transactio data = b"" additional_data = raw_response.get("additionalData", None) - additional_data = [base64.b64decode(data.encode()) - for data in additional_data] if additional_data is not None else [] + additional_data = ( + [base64.b64decode(data.encode()) for data in additional_data] if additional_data is not None else [] + ) if len(additional_data) == 0: if raw_data: @@ -209,7 +224,7 @@ def transaction_events_from_response(raw_response: dict[str, Any]) -> Transactio identifier=identifier, topics=topics, data=data, - additional_data=additional_data + additional_data=additional_data, ) @@ -246,7 +261,7 @@ def transaction_from_simulate_response(original_tx: Transaction, raw_response: d signature=original_tx.signature, status=status, smart_contract_results=sc_results, - logs=TransactionLogs(address=Address.empty(), events=[]) + logs=TransactionLogs(address=Address.empty(), events=[]), ) @@ -258,13 +273,7 @@ def smart_contract_result_from_api_response(raw_response: dict[str, Any]) -> Sma data = raw_response.get("data", "") data = base64.b64decode(data.encode()) - return SmartContractResult( - raw=raw_response, - sender=sender, - receiver=receiver, - data=data, - logs=logs - ) + return SmartContractResult(raw=raw_response, sender=sender, receiver=receiver, data=data, logs=logs) def smart_contract_result_from_proxy_response(raw_response: dict[str, Any]) -> SmartContractResult: @@ -273,13 +282,7 @@ def smart_contract_result_from_proxy_response(raw_response: dict[str, Any]) -> S 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 - ) + return SmartContractResult(raw=raw_response, sender=sender, receiver=receiver, data=data, logs=logs) def network_config_from_response(raw_response: dict[str, Any]) -> NetworkConfig: @@ -305,7 +308,7 @@ def network_config_from_response(raw_response: dict[str, Any]) -> NetworkConfig: num_shards=num_shards, round_duration=round_duration, num_rounds_per_epoch=rounds_per_epoch, - genesis_timestamp=genesis_timestamp + genesis_timestamp=genesis_timestamp, ) @@ -322,7 +325,7 @@ def network_status_from_response(raw_response: dict[str, Any]) -> NetworkStatus: block_nonce=block_nonce, highest_final_block_nonce=highest_final_nonce, current_round=current_round, - current_epoch=currernt_epoch + current_epoch=currernt_epoch, ) @@ -343,7 +346,7 @@ def block_from_response(raw_response: dict[str, Any]) -> BlockOnNetwork: previous_hash=bytes.fromhex(previous_hash), timestamp=timestamp, round=round, - epoch=epoch + epoch=epoch, ) @@ -395,7 +398,7 @@ def account_from_proxy_response(raw_response: dict[str, Any]) -> AccountOnNetwor is_contract_readable=is_readable, is_contract_payable=is_payable, is_contract_payable_by_contract=is_payable_by_sc, - block_coordinates=block_coordinates + block_coordinates=block_coordinates, ) @@ -455,37 +458,26 @@ def account_storage_from_response(raw_response: dict[str, Any]) -> AccountStorag AccountStorageEntry( raw={key: value}, key=decoded_key.decode(errors="ignore"), - value=decoded_value + value=decoded_value, ) ) - return AccountStorage( - raw=raw_response, - entries=entries, - block_coordinates=block_coordinates - ) + return AccountStorage(raw=raw_response, entries=entries, block_coordinates=block_coordinates) def account_storage_entry_from_response(raw_response: dict[str, Any], key: str) -> AccountStorageEntry: value = raw_response.get("value", "") - return AccountStorageEntry( - raw=raw_response, - key=key, - value=bytes.fromhex(value) - ) + return AccountStorageEntry(raw=raw_response, key=key, value=bytes.fromhex(value)) def transaction_cost_estimation_from_response(raw_response: dict[str, Any]) -> TransactionCostResponse: cost = raw_response.get("txGasUnits", 0) - return TransactionCostResponse( - raw=raw_response, - gas_limit=cost, - status=TransactionStatus("") - ) + return TransactionCostResponse(raw=raw_response, gas_limit=cost, status=TransactionStatus("")) -def transactions_from_send_multiple_response(raw_response: dict[str, Any], - initial_txs_sent: int) -> tuple[int, list[bytes]]: +def transactions_from_send_multiple_response( + raw_response: dict[str, Any], initial_txs_sent: int +) -> tuple[int, list[bytes]]: num_sent = raw_response.get("numOfSentTxs", 0) tx_hashes: dict[str, Any] = raw_response.get("txsHashes", {}) @@ -510,7 +502,7 @@ def token_amount_on_network_from_proxy_response(raw_response: dict[str, Any]) -> raw=raw_response, token=token, amount=balance, - block_coordinates=block_coordinates + block_coordinates=block_coordinates, ) @@ -521,11 +513,7 @@ def token_amount_from_api_response(raw_response: dict[str, Any]) -> TokenAmountO # nfts don't have the balance field, thus in case it's nft we set the balance to 1 amount = int(raw_response.get("balance", 1)) - return TokenAmountOnNetwork( - raw=raw_response, - token=Token(identifier, nonce), - amount=amount - ) + return TokenAmountOnNetwork(raw=raw_response, token=Token(identifier, nonce), amount=amount) def token_amounts_from_proxy_response(raw_response: dict[str, Any]) -> list[TokenAmountOnNetwork]: @@ -545,7 +533,7 @@ def token_amounts_from_proxy_response(raw_response: dict[str, Any]) -> list[Toke raw={item: token_data}, token=token, amount=balance, - block_coordinates=block_coordinates + block_coordinates=block_coordinates, ) ) @@ -553,9 +541,8 @@ def token_amounts_from_proxy_response(raw_response: dict[str, Any]) -> list[Toke def definition_of_fungible_token_from_query_response( - raw_response: list[bytes], - identifier: str, - address_hrp: str) -> FungibleTokenMetadata: + raw_response: list[bytes], identifier: str, address_hrp: str +) -> FungibleTokenMetadata: token_name, _, owner, _, _, *properties_buffers = raw_response properties = _parse_token_properties(properties_buffers) @@ -570,7 +557,7 @@ def definition_of_fungible_token_from_query_response( name=name, ticker=ticker, owner=owner.to_bech32(), - decimals=decimals + decimals=decimals, ) @@ -587,14 +574,13 @@ def definition_of_fungible_token_from_api_response(raw_response: dict[str, Any]) name=name, ticker=ticker, owner=owner, - decimals=decimals + decimals=decimals, ) def definition_of_tokens_collection_from_query_response( - raw_response: list[bytes], - identifier: str, - address_hrp: str) -> TokensCollectionMetadata: + raw_response: list[bytes], identifier: str, address_hrp: str +) -> TokensCollectionMetadata: token_name, token_type, owner, _, _, *properties_buffers = raw_response properties = _parse_token_properties(properties_buffers) @@ -612,7 +598,7 @@ def definition_of_tokens_collection_from_query_response( name=name, ticker=ticker, owner=owner.to_bech32(), - decimals=decimals + decimals=decimals, ) @@ -631,7 +617,7 @@ def definition_of_tokens_collection_from_api_response(raw_response: dict[str, An name=name, ticker=ticker, owner=owner, - decimals=decimals + decimals=decimals, ) @@ -667,5 +653,5 @@ def _get_block_coordinates_from_raw_response(raw_response: dict[str, Any]) -> Bl return BlockCoordinates( nonce=block_nonce, hash=bytes.fromhex(block_hash), - root_hash=bytes.fromhex(block_root_hash) + root_hash=bytes.fromhex(block_root_hash), ) diff --git a/multiversx_sdk/network_providers/interface.py b/multiversx_sdk/network_providers/interface.py index 4c5f12a8..93559579 100644 --- a/multiversx_sdk/network_providers/interface.py +++ b/multiversx_sdk/network_providers/interface.py @@ -5,83 +5,74 @@ from multiversx_sdk.core.transaction import Transaction from multiversx_sdk.core.transaction_on_network import TransactionOnNetwork from multiversx_sdk.network_providers.resources import ( - AccountOnNetwork, AccountStorage, AccountStorageEntry, AwaitingOptions, - BlockOnNetwork, FungibleTokenMetadata, NetworkConfig, - NetworkStatus, TokenAmountOnNetwork, TokensCollectionMetadata, - TransactionCostResponse) + AccountOnNetwork, + AccountStorage, + AccountStorageEntry, + AwaitingOptions, + FungibleTokenMetadata, + NetworkConfig, + NetworkStatus, + TokenAmountOnNetwork, + TokensCollectionMetadata, + TransactionCostResponse, +) from multiversx_sdk.smart_contracts.smart_contract_query import ( - SmartContractQuery, SmartContractQueryResponse) + SmartContractQuery, + SmartContractQueryResponse, +) class INetworkProvider(Protocol): - def get_network_config(self) -> NetworkConfig: - ... + def get_network_config(self) -> NetworkConfig: ... - def get_network_status(self, shard: int) -> NetworkStatus: - ... + def get_network_status(self, shard: int) -> NetworkStatus: ... - def get_account(self, address: Address) -> AccountOnNetwork: - ... + def get_account(self, address: Address) -> AccountOnNetwork: ... - def get_account_storage(self, address: Address) -> AccountStorage: - ... + def get_account_storage(self, address: Address) -> AccountStorage: ... - def get_account_storage_entry(self, address: Address, entry_key: str) -> AccountStorageEntry: - ... + def get_account_storage_entry(self, address: Address, entry_key: str) -> AccountStorageEntry: ... def await_account_on_condition( - self, address: Address, condition: Callable[[AccountOnNetwork], - bool], - options: Optional[AwaitingOptions]) -> AccountOnNetwork: - ... + self, + address: Address, + condition: Callable[[AccountOnNetwork], bool], + options: Optional[AwaitingOptions], + ) -> AccountOnNetwork: ... - def send_transaction(self, transaction: Transaction) -> bytes: - ... + def send_transaction(self, transaction: Transaction) -> bytes: ... - def simulate_transaction(self, transaction: Transaction) -> TransactionOnNetwork: - ... + def simulate_transaction(self, transaction: Transaction) -> TransactionOnNetwork: ... - def estimate_transaction_cost(self, transaction: Transaction) -> TransactionCostResponse: - ... + def estimate_transaction_cost(self, transaction: Transaction) -> TransactionCostResponse: ... - def send_transactions(self, transactions: list[Transaction]) -> tuple[int, list[bytes]]: - ... + def send_transactions(self, transactions: list[Transaction]) -> tuple[int, list[bytes]]: ... - def get_transaction(self, transaction_hash: Union[bytes, str]) -> TransactionOnNetwork: - ... + def get_transaction(self, transaction_hash: Union[bytes, str]) -> TransactionOnNetwork: ... def await_transaction_completed( - self, transaction_hash: Union[bytes, str], - options: Optional[AwaitingOptions]) -> TransactionOnNetwork: - ... + self, transaction_hash: Union[bytes, str], options: Optional[AwaitingOptions] + ) -> TransactionOnNetwork: ... def await_transaction_on_condition( - self, transaction_hash: Union[bytes, str], - condition: Callable[[TransactionOnNetwork], - bool], - options: Optional[AwaitingOptions]) -> TransactionOnNetwork: - ... + self, + transaction_hash: Union[bytes, str], + condition: Callable[[TransactionOnNetwork], bool], + options: Optional[AwaitingOptions], + ) -> TransactionOnNetwork: ... - def get_token_of_account(self, address: Address, token: Token) -> TokenAmountOnNetwork: - ... + def get_token_of_account(self, address: Address, token: Token) -> TokenAmountOnNetwork: ... - def get_fungible_tokens_of_account(self, address: Address) -> list[TokenAmountOnNetwork]: - ... + def get_fungible_tokens_of_account(self, address: Address) -> list[TokenAmountOnNetwork]: ... - def get_non_fungible_tokens_of_account(self, address: Address) -> list[TokenAmountOnNetwork]: - ... + def get_non_fungible_tokens_of_account(self, address: Address) -> list[TokenAmountOnNetwork]: ... - def get_definition_of_fungible_token(self, token_identifier: str) -> FungibleTokenMetadata: - ... + def get_definition_of_fungible_token(self, token_identifier: str) -> FungibleTokenMetadata: ... - def get_definition_of_tokens_collection(self, collection_name: str) -> TokensCollectionMetadata: - ... + def get_definition_of_tokens_collection(self, collection_name: str) -> TokensCollectionMetadata: ... - def query_contract(self, query: SmartContractQuery) -> SmartContractQueryResponse: - ... + def query_contract(self, query: SmartContractQuery) -> SmartContractQueryResponse: ... - def do_get_generic(self, url: str, url_parameters: Optional[dict[str, Any]]) -> Any: - ... + def do_get_generic(self, url: str, url_parameters: Optional[dict[str, Any]]) -> Any: ... - def do_post_generic(self, url: str, data: Any, url_parameters: Optional[dict[str, Any]]) -> Any: - ... + def do_post_generic(self, url: str, data: Any, url_parameters: Optional[dict[str, Any]]) -> Any: ... diff --git a/multiversx_sdk/network_providers/proxy_network_provider.py b/multiversx_sdk/network_providers/proxy_network_provider.py index 0025b925..3043f8f3 100644 --- a/multiversx_sdk/network_providers/proxy_network_provider.py +++ b/multiversx_sdk/network_providers/proxy_network_provider.py @@ -18,7 +18,10 @@ BASE_USER_AGENT, DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS, ) -from multiversx_sdk.network_providers.errors import GenericError, TransactionFetchingError +from multiversx_sdk.network_providers.errors import ( + GenericError, + TransactionFetchingError, +) from multiversx_sdk.network_providers.http_resources import ( account_from_proxy_response, account_storage_entry_from_response, @@ -149,9 +152,7 @@ def await_account_on_condition( ) -> AccountOnNetwork: """Waits until an account satisfies a given condition.""" if options is None: - options = AwaitingOptions( - patience_in_milliseconds=DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS - ) + options = AwaitingOptions(patience_in_milliseconds=DEFAULT_ACCOUNT_AWAITING_PATIENCE_IN_MILLISECONDS) awaiter = AccountAwaiter( fetcher=self, @@ -167,9 +168,7 @@ def send_transaction(self, transaction: Transaction) -> bytes: response = self.do_post_generic("transaction/send", transaction.to_dictionary()) return bytes.fromhex(response.get("txHash", "")) - def simulate_transaction( - self, transaction: Transaction, check_signature: bool = False - ) -> TransactionOnNetwork: + def simulate_transaction(self, transaction: Transaction, check_signature: bool = False) -> TransactionOnNetwork: """Simulates a transaction.""" url = "transaction/simulate?checkSignature=false" @@ -177,9 +176,7 @@ def simulate_transaction( url = "transaction/simulate" response = self.do_post_generic(url, transaction.to_dictionary()) - return transaction_from_simulate_response( - transaction, 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.""" @@ -221,7 +218,9 @@ def get_tx() -> dict[str, Any]: return transaction_from_proxy_response(transaction_hash, tx, process_status) def await_transaction_completed( - self, transaction_hash: Union[bytes, str], options: Optional[AwaitingOptions] = None + self, + transaction_hash: Union[bytes, str], + options: Optional[AwaitingOptions] = None, ) -> TransactionOnNetwork: """Waits until the transaction is completely processed.""" transaction_hash = convert_tx_hash_to_string(transaction_hash) @@ -267,9 +266,7 @@ def get_token_of_account(self, address: Address, token: Token) -> TokenAmountOnN if token.nonce == 0: response = self.do_get_generic(f"address/{address.to_bech32()}/esdt/{token.identifier}") else: - response = self.do_get_generic( - f"address/{address.to_bech32()}/nft/{token.identifier}/nonce/{token.nonce}" - ) + response = self.do_get_generic(f"address/{address.to_bech32()}/nft/{token.identifier}/nonce/{token.nonce}") return token_amount_on_network_from_proxy_response(response.to_dictionary()) @@ -336,9 +333,7 @@ def get_transaction_status(self, transaction_hash: Union[str, bytes]) -> Transac response = self.do_get_generic(f"transaction/{transaction_hash}/process-status") return TransactionStatus(response.get("status", "")) - def do_get_generic( - self, url: str, url_parameters: Optional[dict[str, Any]] = None - ) -> GenericResponse: + def do_get_generic(self, url: str, url_parameters: Optional[dict[str, Any]] = None) -> GenericResponse: """Does a generic GET request against the network (handles API enveloping).""" url = f"{self.url}/{url}" @@ -349,9 +344,7 @@ def do_get_generic( response = self._do_get(url) return response - def do_post_generic( - self, url: str, data: Any, url_parameters: Optional[dict[str, Any]] = None - ) -> GenericResponse: + def do_post_generic(self, url: str, data: Any, url_parameters: Optional[dict[str, Any]] = None) -> GenericResponse: """Does a generic GET request against the network (handles API enveloping).""" url = f"{self.url}/{url}" diff --git a/multiversx_sdk/network_providers/proxy_network_provider_test.py b/multiversx_sdk/network_providers/proxy_network_provider_test.py index 0ed565eb..e1dde449 100644 --- a/multiversx_sdk/network_providers/proxy_network_provider_test.py +++ b/multiversx_sdk/network_providers/proxy_network_provider_test.py @@ -1,16 +1,19 @@ import pytest import requests -from multiversx_sdk.core import (Address, Token, Transaction, - TransactionComputer, TransactionOnNetwork, - TransactionStatus) +from multiversx_sdk.core import ( + Address, + Token, + Transaction, + TransactionComputer, + TransactionOnNetwork, + TransactionStatus, +) from multiversx_sdk.network_providers.config import NetworkProviderConfig from multiversx_sdk.network_providers.http_resources import block_from_response -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider from multiversx_sdk.network_providers.resources import TokenAmountOnNetwork -from multiversx_sdk.smart_contracts.smart_contract_query import \ - SmartContractQuery +from multiversx_sdk.smart_contracts.smart_contract_query import SmartContractQuery from multiversx_sdk.testutils.wallets import load_wallets @@ -39,12 +42,12 @@ def test_get_network_status(self): assert result.raw def test_get_block(self): - shard=1 - - block_hash=bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") + shard = 1 + + block_hash = bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") result_by_hash = self.proxy.get_block(shard=shard, block_hash=block_hash) - block_nonce=5949242 + block_nonce = 5949242 result_by_nonce = self.proxy.get_block(shard=shard, block_nonce=block_nonce) assert result_by_hash.hash == bytes.fromhex("ded535cc0afb2dc5f9787e9560dc48d0b83564a3f994a390b228d894d854699f") @@ -58,24 +61,21 @@ def test_get_latest_block(self): assert result def test_get_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") result = self.proxy.get_account(address) assert result.address.to_bech32() == "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" assert not result.username assert result.contract_owner_address is None - address = Address.new_from_bech32( - "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" - ) + address = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen") result = self.proxy.get_account(address) assert result.address.to_bech32() == "erd1qqqqqqqqqqqqqpgq076flgeualrdu5jyyj60snvrh7zu4qrg05vqez5jen" assert not result.username assert result.contract_owner_address == Address.new_from_bech32( - "erd1wzx0tak22f2me4g7wpxfae2w3htfue7khrg28fy6wu8x9hzq05vqm8qhnm") + "erd1wzx0tak22f2me4g7wpxfae2w3htfue7khrg28fy6wu8x9hzq05vqm8qhnm" + ) assert result.is_contract_payable is False assert result.is_contract_readable @@ -95,26 +95,20 @@ def test_get_account_storage_entry(self): assert result.value def test_get_token_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") result = self.proxy.get_token_of_account(address, Token("TEST-ff155e")) assert result.token.identifier == "TEST-ff155e" assert result.amount == 99999999999980000 - result = self.proxy.get_token_of_account( - address, Token("NFTEST-ec88b8", 1) - ) + result = self.proxy.get_token_of_account(address, Token("NFTEST-ec88b8", 1)) assert result.amount == 1 assert result.token.nonce == 1 assert result.token.identifier == "NFTEST-ec88b8" def test_get_fungible_tokens_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") tokens = self.proxy.get_fungible_tokens_of_account(address) assert len(tokens) @@ -124,9 +118,7 @@ def test_get_fungible_tokens_of_account(self): assert filtered[0].amount == 99999999999980000 def test_get_non_fungible_tokens_of_account(self): - address = Address.new_from_bech32( - "erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl" - ) + address = Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl") tokens = self.proxy.get_non_fungible_tokens_of_account(address) assert len(tokens) @@ -146,7 +138,7 @@ def test_query_contract(self): query = SmartContractQuery( contract=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqqy34h7he2ya6qcagqre7ur7cc65vt0mxrc8qnudkr4"), function="getSum", - arguments=[] + arguments=[], ) result = self.proxy.query_contract(query) assert len(result.return_data_parts) == 1 @@ -169,9 +161,7 @@ def test_get_definition_of_token_collection(self): assert len(result.raw["returnDataParts"]) def test_get_transaction(self): - transaction = self.proxy.get_transaction( - "9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c" - ) + transaction = self.proxy.get_transaction("9d47c4b4669cbcaa26f5dec79902dd20e55a0aa5f4b92454a74e7dbd0183ad6c") assert transaction.nonce == 0 assert transaction.epoch == 348 @@ -193,13 +183,14 @@ def test_get_transaction_with_events(self): assert transaction.logs.events[0].topics[2].hex() == "63616e4368616e67654f776e6572" def test_get_sc_invoking_tx(self): - transaction = self.proxy.get_transaction( - "6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb" - ) + transaction = self.proxy.get_transaction("6fe05e4ca01d42c96ae5182978a77fe49f26bcc14aac95ad4f19618173f86ddb") 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 ( + 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): @@ -214,9 +205,9 @@ def test_send_transaction(self): version=2, signature=bytes.fromhex( "faf50b8368cb2c20597dad671a14aa76d4c65937d6e522c64946f16ad6a250262463e444596fa7ee2af1273f6ad0329d43af48d1ae5f3b295bc8f48fdba41a05" - ) + ), ) - expected_hash = ("fc914860c1d137ed8baa602e561381f97c7bad80d150c5bf90760d3cfd3a4cea") + expected_hash = "fc914860c1d137ed8baa602e561381f97c7bad80d150c5bf90760d3cfd3a4cea" assert self.proxy.send_transaction(transaction) == bytes.fromhex(expected_hash) def test_send_transaction_with_data(self): @@ -231,9 +222,9 @@ def test_send_transaction_with_data(self): data=b"foo", signature=bytes.fromhex( "7a8bd08351bac6b1113545f5a896cb0b63806abd93d639bc4d16bfbc82c7b514f68ed7b36c743f4c3d2d1e1d3cb356824041d51dfe587a149f6fc9ab0dd9c408" - ) + ), ) - expected_hash = ("4dc7d4e18c0cf9ca7f17677ef0ac3d1363528e892996b518bee909bb17cf7929") + expected_hash = "4dc7d4e18c0cf9ca7f17677ef0ac3d1363528e892996b518bee909bb17cf7929" assert self.proxy.send_transaction(transaction) == bytes.fromhex(expected_hash) def test_send_transactions(self): @@ -247,7 +238,7 @@ def test_send_transactions(self): version=2, signature=bytes.fromhex( "498d5abb9f8eb69cc75f24320e8929dadbfa855ffac220d5e92175a83be68e0437801af3a1411e3d839738230097a1c38da5c8c4df3f345defc5d40300675900" - ) + ), ) invalid_tx = Transaction( @@ -255,7 +246,7 @@ def test_send_transactions(self): receiver=Address.new_from_bech32("erd1487vz5m4zpxjyqw4flwa3xhnkzg4yrr3mkzf5sf0zgt94hjprc8qazcccl"), gas_limit=50000, chain_id="D", - nonce=77 + nonce=77, ) last_tx = Transaction( @@ -268,7 +259,7 @@ def test_send_transactions(self): version=2, signature=bytes.fromhex( "341a2f3b738fbd20692e3bbd1cb36cb5f4ce9c0a9acc0cf4322269c0fcf34fd6bb59cd94062a9a4730e47f41b1ef3e29b69c6ab2a2a4dca9c9a7724681bc1708" - ) + ), ) transactions = [first_tx, invalid_tx, last_tx] @@ -292,7 +283,7 @@ def test_simulate_transaction(self): receiver=Address.new_from_bech32(bob.label), gas_limit=50000, chain_id="D", - signature=bytes.fromhex("".join(["0"] * 128)) + signature=bytes.fromhex("".join(["0"] * 128)), ) nonce = self.proxy.get_account(Address.new_from_bech32(bob.label)).nonce transaction.nonce = nonce @@ -312,14 +303,16 @@ def test_simulate_transaction(self): chain_id="D", data=b"add@07", nonce=nonce, - signature=bytes.fromhex("".join(["0"] * 128)) + signature=bytes.fromhex("".join(["0"] * 128)), ) tx_on_network = self.proxy.simulate_transaction(transaction) assert tx_on_network.status == TransactionStatus("success") 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].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" @@ -329,8 +322,10 @@ def test_simulate_transaction(self): assert tx_on_network.status == TransactionStatus("success") 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].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" @@ -343,7 +338,7 @@ def test_estimate_transaction_cost(self): receiver=Address.new_from_bech32(bob.label), gas_limit=50000, chain_id="D", - data="test transaction".encode() + data="test transaction".encode(), ) transaction.nonce = self.proxy.get_account(Address.new_from_bech32(bob.label)).nonce transaction.signature = bob.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) @@ -377,7 +372,7 @@ def test_send_and_await_for_completed_transaction(self): receiver=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhdqz9j3zgpl8fg2z0jzx9n605gwxx4djd8ssruw094"), gas_limit=5000000, chain_id="D", - data="dummy@05".encode() + data="dummy@05".encode(), ) transaction.nonce = nonce + 1 transaction.signature = bob.secret_key.sign(tx_computer.compute_bytes_for_signing(transaction)) @@ -387,16 +382,11 @@ def condition(tx: TransactionOnNetwork) -> bool: hash = self.proxy.send_transaction(transaction) - tx_on_network = self.proxy.await_transaction_on_condition( - transaction_hash=hash, - condition=condition - ) + tx_on_network = self.proxy.await_transaction_on_condition(transaction_hash=hash, condition=condition) assert not tx_on_network.status.is_successful def test_do_get_generic(self): - query_params = { - "withTxs": "true" - } + query_params = {"withTxs": "true"} result = self.proxy.do_get_generic(f"block/{1}/by-nonce/{5964199}", query_params) block = block_from_response(result.to_dictionary()) @@ -413,7 +403,7 @@ def test_user_agent(self): # using the new instantiated provider with user agent config = NetworkProviderConfig(client_name="test-client") - proxy = ProxyNetworkProvider(url='https://devnet-gateway.multiversx.com', config=config) + proxy = ProxyNetworkProvider(url="https://devnet-gateway.multiversx.com", config=config) response = requests.get(proxy.url + "/network/config", **proxy.config.requests_options) headers = response.request.headers diff --git a/multiversx_sdk/network_providers/resources.py b/multiversx_sdk/network_providers/resources.py index c768d83b..eac501ce 100644 --- a/multiversx_sdk/network_providers/resources.py +++ b/multiversx_sdk/network_providers/resources.py @@ -5,7 +5,8 @@ from multiversx_sdk.network_providers.constants import ( DEFAULT_TRANSACTION_AWAITING_PATIENCE_IN_MILLISECONDS, DEFAULT_TRANSACTION_AWAITING_POLLING_TIMEOUT_IN_MILLISECONDS, - DEFAULT_TRANSACTION_AWAITING_TIMEOUT_IN_MILLISECONDS) + DEFAULT_TRANSACTION_AWAITING_TIMEOUT_IN_MILLISECONDS, +) class GenericResponse: diff --git a/multiversx_sdk/network_providers/transaction_awaiter.py b/multiversx_sdk/network_providers/transaction_awaiter.py index ff713603..881083a2 100644 --- a/multiversx_sdk/network_providers/transaction_awaiter.py +++ b/multiversx_sdk/network_providers/transaction_awaiter.py @@ -6,9 +6,12 @@ from multiversx_sdk.network_providers.constants import ( DEFAULT_TRANSACTION_AWAITING_PATIENCE_IN_MILLISECONDS, DEFAULT_TRANSACTION_AWAITING_POLLING_TIMEOUT_IN_MILLISECONDS, - DEFAULT_TRANSACTION_AWAITING_TIMEOUT_IN_MILLISECONDS) + DEFAULT_TRANSACTION_AWAITING_TIMEOUT_IN_MILLISECONDS, +) from multiversx_sdk.network_providers.errors import ( - ExpectedTransactionStatusNotReachedError, TransactionFetchingError) + ExpectedTransactionStatusNotReachedError, + TransactionFetchingError, +) ONE_SECOND_IN_MILLISECONDS = 1000 @@ -16,18 +19,19 @@ class ITransactionFetcher(Protocol): - def get_transaction(self, transaction_hash: Union[bytes, str]) -> TransactionOnNetwork: - ... + def get_transaction(self, transaction_hash: Union[bytes, str]) -> TransactionOnNetwork: ... class TransactionAwaiter: """TransactionAwaiter allows one to await until a specific event (such as transaction completion) occurs on a given transaction.""" - def __init__(self, - fetcher: ITransactionFetcher, - polling_interval_in_milliseconds: Optional[int] = None, - timeout_interval_in_milliseconds: Optional[int] = None, - patience_time_in_milliseconds: Optional[int] = None) -> None: + def __init__( + self, + fetcher: ITransactionFetcher, + polling_interval_in_milliseconds: Optional[int] = None, + timeout_interval_in_milliseconds: Optional[int] = None, + patience_time_in_milliseconds: Optional[int] = None, + ) -> None: """ Args: fetcher (ITransactionFetcher): Used to fetch the transaction of the network. @@ -54,6 +58,7 @@ 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): return tx.status.is_completed @@ -63,26 +68,31 @@ def do_fetch(): return self._await_conditionally( is_satisfied=is_completed, do_fetch=do_fetch, - error=ExpectedTransactionStatusNotReachedError() + error=ExpectedTransactionStatusNotReachedError(), ) def await_on_condition( - self, transaction_hash: Union[str, bytes], condition: Callable[[TransactionOnNetwork], - bool]) -> TransactionOnNetwork: + self, + transaction_hash: Union[str, bytes], + condition: Callable[[TransactionOnNetwork], bool], + ) -> TransactionOnNetwork: """Waits until the condition is satisfied.""" + def do_fetch(): return self.fetcher.get_transaction(transaction_hash) return self._await_conditionally( is_satisfied=condition, do_fetch=do_fetch, - error=ExpectedTransactionStatusNotReachedError() + error=ExpectedTransactionStatusNotReachedError(), ) - def _await_conditionally(self, - is_satisfied: Callable[[TransactionOnNetwork], bool], - do_fetch: Callable[[], TransactionOnNetwork], - error: Exception) -> TransactionOnNetwork: + def _await_conditionally( + self, + is_satisfied: Callable[[TransactionOnNetwork], bool], + do_fetch: Callable[[], TransactionOnNetwork], + error: Exception, + ) -> TransactionOnNetwork: is_condition_satisfied = False fetched_data: Union[TransactionOnNetwork, None] = None max_number_of_retries = self.timeout_interval_in_milliseconds // self.polling_interval_in_milliseconds diff --git a/multiversx_sdk/network_providers/transaction_awaiter_test.py b/multiversx_sdk/network_providers/transaction_awaiter_test.py index 1938b2b8..4eca7039 100644 --- a/multiversx_sdk/network_providers/transaction_awaiter_test.py +++ b/multiversx_sdk/network_providers/transaction_awaiter_test.py @@ -5,14 +5,16 @@ from multiversx_sdk.core.transaction_computer import TransactionComputer from multiversx_sdk.core.transaction_on_network import TransactionOnNetwork from multiversx_sdk.core.transaction_status import TransactionStatus -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider -from multiversx_sdk.network_providers.transaction_awaiter import \ - TransactionAwaiter +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider +from multiversx_sdk.network_providers.transaction_awaiter import TransactionAwaiter from multiversx_sdk.testutils.mock_network_provider import ( - MockNetworkProvider, TimelinePointMarkCompleted, TimelinePointWait) -from multiversx_sdk.testutils.mock_transaction_on_network import \ - get_empty_transaction_on_network + MockNetworkProvider, + TimelinePointMarkCompleted, + TimelinePointWait, +) +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_transaction_on_network, +) from multiversx_sdk.testutils.wallets import load_wallets @@ -22,7 +24,7 @@ class TestTransactionAwaiter: fetcher=provider, polling_interval_in_milliseconds=42, timeout_interval_in_milliseconds=42 * 42, - patience_time_in_milliseconds=42 + patience_time_in_milliseconds=42, ) def test_await_status_executed(self): @@ -33,8 +35,13 @@ def test_await_status_executed(self): self.provider.mock_transaction_timeline_by_hash( tx_hash, - [TimelinePointWait(40), TransactionStatus("pending"), TimelinePointWait( - 40), TransactionStatus("executed"), TimelinePointMarkCompleted()] + [ + TimelinePointWait(40), + TransactionStatus("pending"), + TimelinePointWait(40), + TransactionStatus("executed"), + TimelinePointMarkCompleted(), + ], ) tx_from_network = self.watcher.await_completed(tx_hash) @@ -74,8 +81,9 @@ def test_await_on_condition(self): TimelinePointWait(40), TransactionStatus("pending"), TimelinePointWait(40), - TransactionStatus("failed") - ]) + TransactionStatus("failed"), + ], + ) def condition(tx: TransactionOnNetwork) -> bool: return tx.status.status == "failed" diff --git a/multiversx_sdk/network_providers/transaction_decoder.py b/multiversx_sdk/network_providers/transaction_decoder.py index 9631a509..8a61bcd7 100644 --- a/multiversx_sdk/network_providers/transaction_decoder.py +++ b/multiversx_sdk/network_providers/transaction_decoder.py @@ -23,7 +23,7 @@ def to_dict(self) -> dict[str, Any]: "value": self.value, "function_name": self.function_name if self.function_name else "", "function_args": self.function_args if self.function_args else [], - "transfers": self._transfers_to_dict() + "transfers": self._transfers_to_dict(), } def _transfers_to_dict(self) -> list[dict[str, Any]]: @@ -34,11 +34,13 @@ def _transfers_to_dict(self) -> list[dict[str, Any]]: transfers: list[dict[str, Any]] = [] for transfer in self.transfers: - transfers.append({ - "value": transfer.amount, - "token": transfer.token.identifier, - "nonce": transfer.token.nonce - }) + transfers.append( + { + "value": transfer.amount, + "token": transfer.token.identifier, + "nonce": transfer.token.nonce, + } + ) return transfers @@ -78,7 +80,7 @@ def get_normal_transaction_metadata(self, transaction: TransactionOnNetwork) -> metadata.function_args = args if len(args) == 0 and not transaction.receiver.is_smart_contract(): - metadata.function_name = 'transfer' + metadata.function_name = "transfer" metadata.function_args = [] return metadata diff --git a/multiversx_sdk/network_providers/transaction_decoder_test.py b/multiversx_sdk/network_providers/transaction_decoder_test.py index 003604aa..cb142e38 100644 --- a/multiversx_sdk/network_providers/transaction_decoder_test.py +++ b/multiversx_sdk/network_providers/transaction_decoder_test.py @@ -1,10 +1,10 @@ import base64 from multiversx_sdk.core.address import Address -from multiversx_sdk.network_providers.transaction_decoder import \ - TransactionDecoder - -from multiversx_sdk.testutils.mock_transaction_on_network import get_empty_transaction_on_network +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: @@ -13,9 +13,13 @@ class TestTransactionDecoder: def test_nft_smart_contract_call(self) -> None: 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.receiver = Address.new_from_bech32( + "erd18w6yj09l9jwlpj5cjqq9eccfgulkympv7d4rj6vq4u49j8fpwzwsvx7e85" + ) tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAyZmI0ZTlAZTQwZjE2OTk3MTY1NWU2YmIwNGNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGIzNzdmMjYxYzNjNzE5MUA=") + tx_to_decode.data = base64.b64decode( + "RVNEVE5GVFRyYW5zZmVyQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAyZmI0ZTlAZTQwZjE2OTk3MTY1NWU2YmIwNGNAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGIzNzdmMjYxYzNjNzE5MUA=" + ) metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -33,7 +37,9 @@ def test_sc_call(self): 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.receiver = Address.new_from_bech32( + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) tx_to_decode.value = 0 tx_to_decode.data = base64.b64decode("d2l0aGRyYXdHbG9iYWxPZmZlckAwMTczZDA=") @@ -42,14 +48,18 @@ def test_sc_call(self): assert metadata.sender == "erd1wcn58spj6rnsexugjq3p2fxxq4t3l3kt7np078zwkrxu70ul69fqvyjnq2" assert metadata.receiver == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert metadata.function_name == "withdrawGlobalOffer" - assert metadata.function_args == ['0173d0'] + assert metadata.function_args == ["0173d0"] def test_multi_esdt_nft_transfer(self): 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.receiver = Address.new_from_bech32( + "erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9" + ) tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAzMTAyY2FAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGVkZTY0MzExYjhkMDFiNUA=") + tx_to_decode.data = base64.b64decode( + "TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDRjNGI0ZDQ1NTgyZDYxNjE2MjM5MzEzMEAzMTAyY2FAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3Mzc3NjE3MDVmNmM2YjZkNjU3ODVmNzQ2ZjVmNjU2NzZjNjRAMGVkZTY0MzExYjhkMDFiNUA=" + ) metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -74,7 +84,9 @@ def test_esdt_transfer(self): 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.receiver = Address.new_from_bech32( + "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) tx_to_decode.value = 0 tx_to_decode.data = base64.b64decode("RVNEVFRyYW5zZmVyQDU0NDU1MzU0MmQzMjY1MzQzMDY0MzdAMDI1NDBiZTQwMA==") @@ -93,9 +105,13 @@ def test_multi_transfer_fungible_and_meta_esdt(self): 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.receiver = Address.new_from_bech32( + "erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9" + ) tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAMDBAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3MDYxNzk1ZjZkNjU3NDYxNWY2MTZlNjQ1ZjY2NzU2ZTY3Njk2MjZjNjVAMGVkZTY0MzExYjhkMDFiNUA=") + tx_to_decode.data = base64.b64decode( + "TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA0YzRiNGQ0NTU4MmQ2MTYxNjIzOTMxMzBAMmZlM2IwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAMDBAMDEyNjMwZTlhMjlmMmY5MzgxNDQ5MUA3MDYxNzk1ZjZkNjU3NDYxNWY2MTZlNjQ1ZjY2NzU2ZTY3Njk2MjZjNjVAMGVkZTY0MzExYjhkMDFiNUA=" + ) decoder = TransactionDecoder() metadata = decoder.get_transaction_metadata(tx_to_decode) @@ -119,9 +135,13 @@ def test_multi_transfer_fungible_esdt(self): 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.receiver = Address.new_from_bech32( + "erd1lkrrrn3ws9sp854kdpzer9f77eglqpeet3e3k3uxvqxw9p3eq6xqxj43r9" + ) tx_to_decode.value = 0 - tx_to_decode.data = base64.b64decode("TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA1MjQ5NDQ0NTJkMzAzNTYyMzE2MjYyQDAwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAQDAxMjYzMGU5YTI5ZjJmOTM4MTQ0OTE=") + tx_to_decode.data = base64.b64decode( + "TXVsdGlFU0RUTkZUVHJhbnNmZXJAMDAwMDAwMDAwMDAwMDAwMDA1MDBkZjNiZWJlMWFmYTEwYzQwOTI1ZTgzM2MxNGE0NjBlMTBhODQ5ZjUwYTQ2OEAwMkA1MjQ5NDQ0NTJkMzAzNTYyMzE2MjYyQDAwQDA5Yjk5YTZkYjMwMDI3ZTRmM2VjQDU1NTM0NDQzMmQzMzM1MzA2MzM0NjVAQDAxMjYzMGU5YTI5ZjJmOTM4MTQ0OTE=" + ) metadata = self.transaction_decoder.get_transaction_metadata(tx_to_decode) @@ -140,7 +160,9 @@ def test_smart_contract_call_without_args(self): 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.receiver = Address.new_from_bech32( + "erd1qqqqqqqqqqqqqpgqmua7hcd05yxypyj7sv7pffrquy9gf86s535qxct34s" + ) tx_to_decode.value = 0 tx_to_decode.data = base64.b64decode("bXlFbmRwb2ludA==") diff --git a/multiversx_sdk/network_providers/user_agent.py b/multiversx_sdk/network_providers/user_agent.py index c0b72460..926984f2 100644 --- a/multiversx_sdk/network_providers/user_agent.py +++ b/multiversx_sdk/network_providers/user_agent.py @@ -9,12 +9,18 @@ def extend_user_agent(user_agent_prefix: str, config: NetworkProviderConfig): if config.client_name is None: - logger.info("We recommend providing the `client_name` when instantiating a NetworkProvider (e.g. ProxyNetworkProvider, ApiNetworkProvider). This information will be used for metrics collection and improving our services.") + logger.info( + "We recommend providing the `client_name` when instantiating a NetworkProvider (e.g. ProxyNetworkProvider, ApiNetworkProvider). This information will be used for metrics collection and improving our services." + ) headers: dict[str, Any] = config.requests_options.setdefault("headers", {}) resolved_client_name = config.client_name or UNKNOWN_CLIENT_NAME current_user_agent = headers.get("User-Agent", "") - new_user_agent = f"{current_user_agent} {user_agent_prefix}/{resolved_client_name}" if current_user_agent else f"{user_agent_prefix}/{resolved_client_name}" + new_user_agent = ( + f"{current_user_agent} {user_agent_prefix}/{resolved_client_name}" + if current_user_agent + else f"{user_agent_prefix}/{resolved_client_name}" + ) headers["User-Agent"] = new_user_agent diff --git a/multiversx_sdk/relayed/__init__.py b/multiversx_sdk/relayed/__init__.py index a6a246e8..d09ea798 100644 --- a/multiversx_sdk/relayed/__init__.py +++ b/multiversx_sdk/relayed/__init__.py @@ -1,5 +1,6 @@ from multiversx_sdk.relayed.relayed_controller import RelayedController -from multiversx_sdk.relayed.relayed_transactions_factory import \ - RelayedTransactionsFactory +from multiversx_sdk.relayed.relayed_transactions_factory import ( + RelayedTransactionsFactory, +) __all__ = ["RelayedTransactionsFactory", "RelayedController"] diff --git a/multiversx_sdk/relayed/relayed_transactions_factory.py b/multiversx_sdk/relayed/relayed_transactions_factory.py index 334f544c..0871cb71 100644 --- a/multiversx_sdk/relayed/relayed_transactions_factory.py +++ b/multiversx_sdk/relayed/relayed_transactions_factory.py @@ -5,8 +5,7 @@ from multiversx_sdk.abi import AddressValue, BigUIntValue, Serializer from multiversx_sdk.abi.bytes_value import BytesValue from multiversx_sdk.core import Address, Transaction -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.relayed.errors import InvalidInnerTransactionError @@ -15,59 +14,56 @@ class RelayedTransactionsFactory: The Relayed Transactions V1 and V2 will soon be deprecated from the network. Please use Relayed Transactions V3 instead. The transactions are created from the perspective of the relayer. The 'sender' represents the relayer. """ - + def __init__(self, config: TransactionsFactoryConfig) -> None: self._config = config - def create_relayed_v1_transaction(self, - inner_transaction: Transaction, - relayer_address: Address) -> Transaction: + def create_relayed_v1_transaction(self, inner_transaction: Transaction, relayer_address: Address) -> Transaction: if not inner_transaction.gas_limit: - raise InvalidInnerTransactionError( - "The gas limit is not set for the inner transaction") + raise InvalidInnerTransactionError("The gas limit is not set for the inner transaction") if not inner_transaction.signature: - raise InvalidInnerTransactionError( - "The inner transaction is not signed") + raise InvalidInnerTransactionError("The inner transaction is not signed") - serialized_transaction = self._prepare_inner_transaction_for_relayed_v1( - inner_transaction) + serialized_transaction = self._prepare_inner_transaction_for_relayed_v1(inner_transaction) data = f"relayedTx@{serialized_transaction.encode().hex()}" - gas_limit = self._config.min_gas_limit + self._config.gas_limit_per_byte * \ - len(data) + inner_transaction.gas_limit + gas_limit = ( + self._config.min_gas_limit + self._config.gas_limit_per_byte * len(data) + inner_transaction.gas_limit + ) return Transaction( chain_id=self._config.chain_id, sender=relayer_address, receiver=inner_transaction.sender, gas_limit=gas_limit, - data=data.encode() + data=data.encode(), ) - def create_relayed_v2_transaction(self, - inner_transaction: Transaction, - inner_transaction_gas_limit: int, - relayer_address: Address) -> Transaction: + def create_relayed_v2_transaction( + self, + inner_transaction: Transaction, + inner_transaction_gas_limit: int, + relayer_address: Address, + ) -> Transaction: if inner_transaction.gas_limit: - raise InvalidInnerTransactionError( - "The gas limit should not be set for the inner transaction") + raise InvalidInnerTransactionError("The gas limit should not be set for the inner transaction") if not inner_transaction.signature: - raise InvalidInnerTransactionError( - "The inner transaction is not signed") + raise InvalidInnerTransactionError("The inner transaction is not signed") arguments: list[Any] = [ AddressValue.new_from_address(inner_transaction.receiver), BigUIntValue(inner_transaction.nonce), BytesValue(inner_transaction.data), - BytesValue(inner_transaction.signature) + BytesValue(inner_transaction.signature), ] serializer = Serializer() data = f"relayedTxV2@{serializer.serialize(arguments)}" - gas_limit = inner_transaction_gas_limit + self._config.min_gas_limit + \ - self._config.gas_limit_per_byte * len(data) + gas_limit = ( + inner_transaction_gas_limit + self._config.min_gas_limit + self._config.gas_limit_per_byte * len(data) + ) return Transaction( sender=relayer_address, @@ -77,7 +73,7 @@ def create_relayed_v2_transaction(self, chain_id=self._config.chain_id, data=data.encode(), version=inner_transaction.version, - options=inner_transaction.options + options=inner_transaction.options, ) def _prepare_inner_transaction_for_relayed_v1(self, inner_transaction: Transaction) -> str: diff --git a/multiversx_sdk/relayed/relayed_transactions_factory_test.py b/multiversx_sdk/relayed/relayed_transactions_factory_test.py index e6c00b2a..b35ea804 100644 --- a/multiversx_sdk/relayed/relayed_transactions_factory_test.py +++ b/multiversx_sdk/relayed/relayed_transactions_factory_test.py @@ -1,11 +1,11 @@ import pytest from multiversx_sdk.core import Address, Transaction, TransactionComputer -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.relayed.errors import InvalidInnerTransactionError -from multiversx_sdk.relayed.relayed_transactions_factory import \ - RelayedTransactionsFactory +from multiversx_sdk.relayed.relayed_transactions_factory import ( + RelayedTransactionsFactory, +) from multiversx_sdk.testutils.wallets import load_wallets @@ -23,22 +23,25 @@ def test_create_relayed_v1_with_invalid_inner_tx(self): receiver=Address.new_from_bech32("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), gas_limit=10000000, data="getContractConfig".encode(), - chain_id=self.config.chain_id + chain_id=self.config.chain_id, ) with pytest.raises(InvalidInnerTransactionError, match="The inner transaction is not signed"): self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(self.wallets["bob"].label) + relayer_address=Address.from_bech32(self.wallets["bob"].label), ) inner_transaction.gas_limit = 0 inner_transaction.signature = b"invalidsignature" - with pytest.raises(InvalidInnerTransactionError, match="The gas limit is not set for the inner transaction"): + with pytest.raises( + InvalidInnerTransactionError, + match="The gas limit is not set for the inner transaction", + ): self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(self.wallets["bob"].label) + relayer_address=Address.from_bech32(self.wallets["bob"].label), ) def test_create_relayed_v1_transaction(self): @@ -51,7 +54,7 @@ def test_create_relayed_v1_transaction(self): gas_limit=60000000, chain_id=self.config.chain_id, data=b"getContractConfig", - nonce=198 + nonce=198, ) inner_tx_bytes = self.transaction_computer.compute_bytes_for_signing(inner_transaction) @@ -59,16 +62,21 @@ def test_create_relayed_v1_transaction(self): relayed_transaction = self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(alice.label) + relayer_address=Address.from_bech32(alice.label), ) relayed_transaction.nonce = 2627 relayed_tx_bytes = self.transaction_computer.compute_bytes_for_signing(relayed_transaction) relayed_transaction.signature = alice.secret_key.sign(relayed_tx_bytes) - assert relayed_transaction.data.decode() == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414141415141414141414141414141414141414141414141414141414141432f2f383d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225a3256305132397564484a68593352446232356d6157633d222c227369676e6174757265223a2272525455544858677a4273496e4f6e454b6b7869642b354e66524d486e33534948314673746f577352434c434b3258514c41614f4e704449346531476173624c5150616130566f364144516d4f2b52446b6f364a43413d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a327d" - assert relayed_transaction.signature.hex( - ) == "128e7cdc14c2b9beee2f3ff7a7fa5d1f5ef31a654a0c92e223c90ab28265fa277d306f23a06536248cf9573e828017004fb639617fade4d68a37524aafca710d" + assert ( + relayed_transaction.data.decode() + == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414141415141414141414141414141414141414141414141414141414141432f2f383d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225a3256305132397564484a68593352446232356d6157633d222c227369676e6174757265223a2272525455544858677a4273496e4f6e454b6b7869642b354e66524d486e33534948314673746f577352434c434b3258514c41614f4e704449346531476173624c5150616130566f364144516d4f2b52446b6f364a43413d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a327d" + ) + assert ( + relayed_transaction.signature.hex() + == "128e7cdc14c2b9beee2f3ff7a7fa5d1f5ef31a654a0c92e223c90ab28265fa277d306f23a06536248cf9573e828017004fb639617fade4d68a37524aafca710d" + ) def test_create_relayed_v1_transaction_with_usernames(self): alice = self.wallets["alice"] @@ -83,7 +91,7 @@ def test_create_relayed_v1_transaction_with_usernames(self): nonce=208, sender_username="carol", receiver_username="alice", - value=1000000000000000000 + value=1000000000000000000, ) inner_tx_bytes = self.transaction_computer.compute_bytes_for_signing(inner_transaction) @@ -91,16 +99,21 @@ def test_create_relayed_v1_transaction_with_usernames(self): relayed_transaction = self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(frank.label) + relayer_address=Address.from_bech32(frank.label), ) relayed_transaction.nonce = 715 relayed_tx_bytes = self.transaction_computer.compute_bytes_for_signing(relayed_transaction) relayed_transaction.signature = frank.secret_key.sign(relayed_tx_bytes) - assert relayed_transaction.data.decode() == "relayedTx@7b226e6f6e6365223a3230382c2273656e646572223a227371455656633553486b6c45344a717864556e59573068397a536249533141586f3534786f32634969626f3d222c227265636569766572223a2241546c484c76396f686e63616d433877673970645168386b77704742356a6949496f3349484b594e6165453d222c2276616c7565223a313030303030303030303030303030303030302c226761735072696365223a313030303030303030302c226761734c696d6974223a35303030302c2264617461223a22222c227369676e6174757265223a226a33427a6469554144325963517473576c65707663664a6f75657a48573063316b735a424a4d6339573167435450512b6870636759457858326f6f367a4b5654347464314b4b6f79783841526a346e336474576c44413d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c22736e64557365724e616d65223a22593246796232773d222c22726376557365724e616d65223a22595778705932553d227d" - assert relayed_transaction.signature.hex( - ) == "3787d640e5a579e7977a4a1bcdd435ad11855632fa4a414a06fbf8355692d1a58d76ef0adbdd6ccd6bd3c329f36bd53c180d4873ec1a6c558e659aeb9ab92d00" + assert ( + relayed_transaction.data.decode() + == "relayedTx@7b226e6f6e6365223a3230382c2273656e646572223a227371455656633553486b6c45344a717864556e59573068397a536249533141586f3534786f32634969626f3d222c227265636569766572223a2241546c484c76396f686e63616d433877673970645168386b77704742356a6949496f3349484b594e6165453d222c2276616c7565223a313030303030303030303030303030303030302c226761735072696365223a313030303030303030302c226761734c696d6974223a35303030302c2264617461223a22222c227369676e6174757265223a226a33427a6469554144325963517473576c65707663664a6f75657a48573063316b735a424a4d6339573167435450512b6870636759457858326f6f367a4b5654347464314b4b6f79783841526a346e336474576c44413d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c22736e64557365724e616d65223a22593246796232773d222c22726376557365724e616d65223a22595778705932553d227d" + ) + assert ( + relayed_transaction.signature.hex() + == "3787d640e5a579e7977a4a1bcdd435ad11855632fa4a414a06fbf8355692d1a58d76ef0adbdd6ccd6bd3c329f36bd53c180d4873ec1a6c558e659aeb9ab92d00" + ) def test_compute_relayed_v1_with_guarded_inner_tx(self): alice = self.wallets["alice"] @@ -116,7 +129,7 @@ def test_compute_relayed_v1_with_guarded_inner_tx(self): nonce=198, version=2, options=2, - guardian=Address.new_from_bech32(grace.label) + guardian=Address.new_from_bech32(grace.label), ) inner_tx_bytes = self.transaction_computer.compute_bytes_for_signing(inner_transaction) @@ -125,16 +138,21 @@ def test_compute_relayed_v1_with_guarded_inner_tx(self): relayed_transaction = self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(alice.label) + relayer_address=Address.from_bech32(alice.label), ) relayed_transaction.nonce = 2627 relayed_tx_bytes = self.transaction_computer.compute_bytes_for_signing(relayed_transaction) relayed_transaction.signature = alice.secret_key.sign(relayed_tx_bytes) - assert relayed_transaction.data.decode() == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414146414b565841323879704877692f79693741364c64504b704f68464d386958513d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225a3256305132397564484a68593352446232356d6157633d222c227369676e6174757265223a224b4b78324f33383655725135416b4f465258307578327933446a384853334b373038487174344668377161557669424550716c45614e746e6158706a6f2f333651476d4a456934784435457a6c6f4f677a634d4442773d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c226f7074696f6e73223a322c22677561726469616e223a22486f714c61306e655733766843716f56696c70715372744c5673774939535337586d7a563868477450684d3d222c22677561726469616e5369676e6174757265223a222b5431526f4833625a792f54423177342b6a365155477258645637457577553073753948646551626453515269463953757a686d634b705463526d58595252366c534c6652394931624d7134674730436538363741513d3d227d" - assert relayed_transaction.signature.hex( - ) == "39cff9d5100e290fbc7361cb6e2402261caf864257b4116f150e0c61e7869155dff8361fa5449431eb7a8ed847c01ba9b3b5ebafe5fac1a3d40c64829d827e00" + assert ( + relayed_transaction.data.decode() + == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414146414b565841323879704877692f79693741364c64504b704f68464d386958513d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225a3256305132397564484a68593352446232356d6157633d222c227369676e6174757265223a224b4b78324f33383655725135416b4f465258307578327933446a384853334b373038487174344668377161557669424550716c45614e746e6158706a6f2f333651476d4a456934784435457a6c6f4f677a634d4442773d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c226f7074696f6e73223a322c22677561726469616e223a22486f714c61306e655733766843716f56696c70715372744c5673774939535337586d7a563868477450684d3d222c22677561726469616e5369676e6174757265223a222b5431526f4833625a792f54423177342b6a365155477258645637457577553073753948646551626453515269463953757a686d634b705463526d58595252366c534c6652394931624d7134674730436538363741513d3d227d" + ) + assert ( + relayed_transaction.signature.hex() + == "39cff9d5100e290fbc7361cb6e2402261caf864257b4116f150e0c61e7869155dff8361fa5449431eb7a8ed847c01ba9b3b5ebafe5fac1a3d40c64829d827e00" + ) def test_guarded_relayed_v1_with_guarded_inner_tx(self): alice = self.wallets["alice"] @@ -151,7 +169,7 @@ def test_guarded_relayed_v1_with_guarded_inner_tx(self): nonce=198, version=2, options=2, - guardian=Address.new_from_bech32(grace.label) + guardian=Address.new_from_bech32(grace.label), ) inner_tx_bytes = self.transaction_computer.compute_bytes_for_signing(inner_transaction) @@ -160,7 +178,7 @@ def test_guarded_relayed_v1_with_guarded_inner_tx(self): relayed_transaction = self.factory.create_relayed_v1_transaction( inner_transaction=inner_transaction, - relayer_address=Address.from_bech32(alice.label) + relayer_address=Address.from_bech32(alice.label), ) relayed_transaction.options = 2 relayed_transaction.nonce = 2627 @@ -170,9 +188,14 @@ def test_guarded_relayed_v1_with_guarded_inner_tx(self): relayed_transaction.signature = alice.secret_key.sign(relayed_tx_bytes) relayed_transaction.guardian_signature = frank.secret_key.sign(relayed_tx_bytes) - assert relayed_transaction.data.decode() == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414146414b565841323879704877692f79693741364c64504b704f68464d386958513d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225957526b546e5674596d5679222c227369676e6174757265223a223469724d4b4a656d724d375174344e7635487633544c44683775654779487045564c4371674a3677652f7a662b746a4933354975573452633458543451533433475333356158386c6a533834324a38426854645043673d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c226f7074696f6e73223a322c22677561726469616e223a22486f714c61306e655733766843716f56696c70715372744c5673774939535337586d7a563868477450684d3d222c22677561726469616e5369676e6174757265223a2270424754394e674a78307539624c56796b654d78786a454865374269696c37764932324a46676f32787a6e2f496e3032463769546563356b44395045324f747065386c475335412b532f4a36417762576834446744673d3d227d" - assert relayed_transaction.signature.hex( - ) == "8ede1bbeed96b102344dffeac12c2592c62b7313cdeb132e8c8bf11d2b1d3bb8189d257a6dbcc99e222393d9b9ec77656c349dae97a32e68bdebd636066bf706" + assert ( + relayed_transaction.data.decode() + == "relayedTx@7b226e6f6e6365223a3139382c2273656e646572223a2267456e574f65576d6d413063306a6b71764d354241707a61644b46574e534f69417643575163776d4750673d222c227265636569766572223a22414141414141414141414146414b565841323879704877692f79693741364c64504b704f68464d386958513d222c2276616c7565223a302c226761735072696365223a313030303030303030302c226761734c696d6974223a36303030303030302c2264617461223a225957526b546e5674596d5679222c227369676e6174757265223a223469724d4b4a656d724d375174344e7635487633544c44683775654779487045564c4371674a3677652f7a662b746a4933354975573452633458543451533433475333356158386c6a533834324a38426854645043673d3d222c22636861696e4944223a2256413d3d222c2276657273696f6e223a322c226f7074696f6e73223a322c22677561726469616e223a22486f714c61306e655733766843716f56696c70715372744c5673774939535337586d7a563868477450684d3d222c22677561726469616e5369676e6174757265223a2270424754394e674a78307539624c56796b654d78786a454865374269696c37764932324a46676f32787a6e2f496e3032463769546563356b44395045324f747065386c475335412b532f4a36417762576834446744673d3d227d" + ) + assert ( + relayed_transaction.signature.hex() + == "8ede1bbeed96b102344dffeac12c2592c62b7313cdeb132e8c8bf11d2b1d3bb8189d257a6dbcc99e222393d9b9ec77656c349dae97a32e68bdebd636066bf706" + ) def test_create_relayed_v2_with_invalid_inner_tx(self): alice = self.wallets["alice"] @@ -183,14 +206,17 @@ def test_create_relayed_v2_with_invalid_inner_tx(self): sender=Address.new_from_bech32(alice.label), receiver=Address.new_from_bech32(bob.label), gas_limit=50000, - chain_id=self.config.chain_id + chain_id=self.config.chain_id, ) - with pytest.raises(InvalidInnerTransactionError, match="The gas limit should not be set for the inner transaction"): + with pytest.raises( + InvalidInnerTransactionError, + match="The gas limit should not be set for the inner transaction", + ): self.factory.create_relayed_v2_transaction( inner_transaction=inner_transaction, inner_transaction_gas_limit=50000, - relayer_address=Address.from_bech32(carol.label) + relayer_address=Address.from_bech32(carol.label), ) inner_transaction.gas_limit = 0 @@ -198,7 +224,7 @@ def test_create_relayed_v2_with_invalid_inner_tx(self): self.factory.create_relayed_v2_transaction( inner_transaction=inner_transaction, inner_transaction_gas_limit=50000, - relayer_address=Address.from_bech32(carol.label) + relayer_address=Address.from_bech32(carol.label), ) def test_compute_relayed_v2_transaction(self): @@ -213,7 +239,7 @@ def test_compute_relayed_v2_transaction(self): data=b"getContractConfig", nonce=15, version=2, - options=0 + options=0, ) serialized_inner_transaction = self.transaction_computer.compute_bytes_for_signing(inner_transaction) @@ -222,7 +248,7 @@ def test_compute_relayed_v2_transaction(self): relayed_transaction = self.factory.create_relayed_v2_transaction( inner_transaction=inner_transaction, inner_transaction_gas_limit=60_000_000, - relayer_address=Address.from_bech32(alice.label) + relayer_address=Address.from_bech32(alice.label), ) relayed_transaction.nonce = 37 @@ -232,4 +258,7 @@ 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" + assert ( + relayed_transaction.data.decode() + == "relayedTxV2@000000000000000000010000000000000000000000000000000000000002ffff@0f@676574436f6e7472616374436f6e666967@fc3ed87a51ee659f937c1a1ed11c1ae677e99629fae9cc289461f033e6514d1a8cfad1144ae9c1b70f28554d196bd6ba1604240c1c1dc19c959e96c1c3b62d0c" + ) diff --git a/multiversx_sdk/smart_contracts/__init__.py b/multiversx_sdk/smart_contracts/__init__.py index c70284a0..695f3b62 100644 --- a/multiversx_sdk/smart_contracts/__init__.py +++ b/multiversx_sdk/smart_contracts/__init__.py @@ -1,17 +1,29 @@ -from multiversx_sdk.smart_contracts.smart_contract_controller import \ - SmartContractController +from multiversx_sdk.smart_contracts.smart_contract_controller import ( + SmartContractController, +) from multiversx_sdk.smart_contracts.smart_contract_query import ( - SmartContractQuery, SmartContractQueryResponse) -from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import \ - SmartContractTransactionsFactory -from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import \ - SmartContractTransactionsOutcomeParser + SmartContractQuery, + SmartContractQueryResponse, +) +from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import ( + SmartContractTransactionsFactory, +) +from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import ( + SmartContractTransactionsOutcomeParser, +) from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser_types import ( - DeployedSmartContract, ParsedSmartContractCallOutcome, - SmartContractDeployOutcome) + DeployedSmartContract, + ParsedSmartContractCallOutcome, + SmartContractDeployOutcome, +) __all__ = [ - "SmartContractQuery", "SmartContractQueryResponse", "SmartContractTransactionsFactory", - "SmartContractController", "SmartContractTransactionsOutcomeParser", "DeployedSmartContract", - "ParsedSmartContractCallOutcome", "SmartContractDeployOutcome" + "SmartContractQuery", + "SmartContractQueryResponse", + "SmartContractTransactionsFactory", + "SmartContractController", + "SmartContractTransactionsOutcomeParser", + "DeployedSmartContract", + "ParsedSmartContractCallOutcome", + "SmartContractDeployOutcome", ] diff --git a/multiversx_sdk/smart_contracts/errors.py b/multiversx_sdk/smart_contracts/errors.py index 0f4172f6..75cb8b07 100644 --- a/multiversx_sdk/smart_contracts/errors.py +++ b/multiversx_sdk/smart_contracts/errors.py @@ -1,4 +1,3 @@ - class SmartContractQueryError(Exception): def __init__(self, return_code: str, message: str) -> None: super().__init__(message) @@ -6,5 +5,8 @@ def __init__(self, return_code: str, message: str) -> None: class ArgumentSerializationError(Exception): - def __init__(self, message: str = "Unable to encode arguments: unsupported format or missing ABI file") -> None: + def __init__( + self, + message: str = "Unable to encode arguments: unsupported format or missing ABI file", + ) -> None: super().__init__(message) diff --git a/multiversx_sdk/smart_contracts/smart_contract_controller.py b/multiversx_sdk/smart_contracts/smart_contract_controller.py index 9b26ca19..79f27d44 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_controller.py +++ b/multiversx_sdk/smart_contracts/smart_contract_controller.py @@ -44,7 +44,12 @@ def await_transaction_completed( class SmartContractController(BaseController): - def __init__(self, chain_id: str, network_provider: INetworkProvider, abi: Optional[Abi] = None) -> None: + def __init__( + self, + chain_id: str, + network_provider: INetworkProvider, + abi: Optional[Abi] = None, + ) -> None: self.abi = abi self.factory = SmartContractTransactionsFactory(TransactionsFactoryConfig(chain_id), abi=self.abi) self.parser = SmartContractTransactionsOutcomeParser(abi=self.abi) @@ -165,7 +170,9 @@ def create_transaction_for_execute( return transaction def parse_execute( - self, transaction_on_network: TransactionOnNetwork, function: Optional[str] = None + self, + transaction_on_network: TransactionOnNetwork, + function: Optional[str] = None, ) -> ParsedSmartContractCallOutcome: return self.parser.parse_execute(transaction_on_network, function) @@ -182,7 +189,13 @@ def query( value: Optional[int] = None, ) -> list[Any]: """It calls `create_query()`, `run_query()` and `parse_query_response()` in one go.""" - query = self.create_query(contract=contract, function=function, arguments=arguments, caller=caller, value=value) + query = self.create_query( + contract=contract, + function=function, + arguments=arguments, + caller=caller, + value=value, + ) query_response = self.run_query(query) self._raise_for_status(query_response) diff --git a/multiversx_sdk/smart_contracts/smart_contract_controller_test.py b/multiversx_sdk/smart_contracts/smart_contract_controller_test.py index 1b89be8d..d1edc347 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_controller_test.py +++ b/multiversx_sdk/smart_contracts/smart_contract_controller_test.py @@ -9,12 +9,14 @@ from multiversx_sdk.accounts.account import Account from multiversx_sdk.core.address import Address from multiversx_sdk.core.constants import CONTRACT_DEPLOY_ADDRESS_HEX -from multiversx_sdk.network_providers.api_network_provider import \ - ApiNetworkProvider -from multiversx_sdk.smart_contracts.smart_contract_controller import \ - SmartContractController +from multiversx_sdk.network_providers.api_network_provider import ApiNetworkProvider +from multiversx_sdk.smart_contracts.smart_contract_controller import ( + SmartContractController, +) from multiversx_sdk.smart_contracts.smart_contract_query import ( - SmartContractQuery, SmartContractQueryResponse) + SmartContractQuery, + SmartContractQueryResponse, +) from multiversx_sdk.testutils.mock_network_provider import MockNetworkProvider @@ -34,7 +36,7 @@ def test_create_transaction_for_deploy(self): nonce=self.alice.get_nonce_then_increment(), bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[BigUIntValue(1)] + arguments=[BigUIntValue(1)], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -55,7 +57,7 @@ def test_create_transaction_for_execute(self): contract=contract, function=function, gas_limit=gas_limit, - arguments=[U32Value(7)] + arguments=[U32Value(7)], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -75,7 +77,7 @@ def test_create_transaction_for_upgrade(self): contract=contract_address, bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[BigUIntValue(0)] + arguments=[BigUIntValue(0)], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -89,11 +91,7 @@ def test_create_query_without_arguments(self): contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqsnwuj85zv7t0wnxfetyqqyjvvg444lpk7uasxv8ktx") function = "getSum" - query = controller.create_query( - contract=contract, - function=function, - arguments=[] - ) + query = controller.create_query(contract=contract, function=function, arguments=[]) assert query.contract == contract assert query.function == function @@ -109,12 +107,12 @@ def test_create_query_with_arguments(self): query = controller.create_query( contract=contract, function=function, - arguments=[U64Value(7), StringValue("abba")] + arguments=[U64Value(7), StringValue("abba")], ) assert query.contract == contract assert query.function == function - assert query.arguments == [b'\x07', b"abba"] + assert query.arguments == [b"\x07", b"abba"] assert query.caller is None assert query.value is None @@ -124,16 +122,10 @@ def test_create_query_with_arguments_with_abi(self): contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqsnwuj85zv7t0wnxfetyqqyjvvg444lpk7uasxv8ktx") function = "getLotteryInfo" - query = controller.create_query( - contract=contract, - function=function, - arguments=["myLottery"] - ) + query = controller.create_query(contract=contract, function=function, arguments=["myLottery"]) query_with_typed = controller.create_query( - contract=contract, - function=function, - arguments=[StringValue("myLottery")] + contract=contract, function=function, arguments=[StringValue("myLottery")] ) assert query.contract == contract @@ -152,7 +144,7 @@ def test_run_query_with_mock_provider(self): function="bar", return_code="ok", return_message="", - return_data_parts=["abba".encode()] + return_data_parts=["abba".encode()], ) network_provider.mock_query_contract_on_function("bar", contract_query_response) @@ -160,7 +152,7 @@ def test_run_query_with_mock_provider(self): query = SmartContractQuery( contract=Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqvc7gdl0p4s97guh498wgz75k8sav6sjfjlwqh679jy"), function="bar", - arguments=[] + arguments=[], ) response = controller.run_query(query) @@ -174,7 +166,7 @@ def test_parse_query_response(self): function="bar", return_code="ok", return_message="ok", - return_data_parts=["abba".encode()] + return_data_parts=["abba".encode()], ) parsed = controller.parse_query_response(response) @@ -188,16 +180,19 @@ def test_parse_query_response_with_abi(self): function="getLotteryInfo", return_code="ok", return_message="ok", - return_data_parts=[bytes.fromhex( - "0000000b6c75636b792d746f6b656e000000010100000000000000005fc2b9dbffffffff00000001640000000a140ec80fa7ee88000000")] + return_data_parts=[ + bytes.fromhex( + "0000000b6c75636b792d746f6b656e000000010100000000000000005fc2b9dbffffffff00000001640000000a140ec80fa7ee88000000" + ) + ], ) [lottery_info] = controller.parse_query_response(response) assert lottery_info.token_identifier == "lucky-token" assert lottery_info.ticket_price == 1 assert lottery_info.tickets_left == 0 - assert lottery_info.deadline == 0x000000005fc2b9db - assert lottery_info.max_entries_per_user == 0xffffffff + assert lottery_info.deadline == 0x000000005FC2B9DB + assert lottery_info.max_entries_per_user == 0xFFFFFFFF assert lottery_info.prize_distribution == bytes([0x64]) assert lottery_info.prize_pool == 94720000000000000000000 @@ -208,16 +203,12 @@ def test_run_query_on_network(self): contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqsnwuj85zv7t0wnxfetyqqyjvvg444lpk7uasxv8ktx") function = "getSum" - query = controller.create_query( - contract=contract, - function=function, - arguments=[] - ) + query = controller.create_query(contract=contract, function=function, arguments=[]) query_response = controller.run_query(query) assert query_response.return_code == "ok" assert query_response.return_message == "" - assert query_response.return_data_parts == [b'\x05'] + assert query_response.return_data_parts == [b"\x05"] @pytest.mark.networkInteraction def test_query_on_network(self): @@ -226,10 +217,6 @@ def test_query_on_network(self): contract = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqsnwuj85zv7t0wnxfetyqqyjvvg444lpk7uasxv8ktx") function = "getSum" - return_data_parts = controller.query( - contract=contract, - function=function, - arguments=[] - ) + return_data_parts = controller.query(contract=contract, function=function, arguments=[]) - assert return_data_parts == [b'\x05'] + assert return_data_parts == [b"\x05"] diff --git a/multiversx_sdk/smart_contracts/smart_contract_query.py b/multiversx_sdk/smart_contracts/smart_contract_query.py index bc499555..8e39cb26 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_query.py +++ b/multiversx_sdk/smart_contracts/smart_contract_query.py @@ -4,12 +4,14 @@ class SmartContractQuery: - def __init__(self, - contract: Address, - function: str, - arguments: list[bytes], - caller: Optional[Address] = None, - value: Optional[int] = None) -> None: + def __init__( + self, + contract: Address, + function: str, + arguments: list[bytes], + caller: Optional[Address] = None, + value: Optional[int] = None, + ) -> None: self.contract = contract self.function = function self.arguments = arguments @@ -24,11 +26,13 @@ def __eq__(self, other: object) -> bool: class SmartContractQueryResponse: - def __init__(self, - function: str, - return_code: str, - return_message: str, - return_data_parts: list[bytes]) -> None: + def __init__( + self, + function: str, + return_code: str, + return_message: str, + return_data_parts: list[bytes], + ) -> None: self.function = function self.return_code = return_code self.return_message = return_message diff --git a/multiversx_sdk/smart_contracts/smart_contract_transaction_factory_test.py b/multiversx_sdk/smart_contracts/smart_contract_transaction_factory_test.py index 26b04733..1485c6d5 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transaction_factory_test.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transaction_factory_test.py @@ -8,11 +8,11 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.constants import CONTRACT_DEPLOY_ADDRESS_HEX from multiversx_sdk.core.tokens import Token, TokenTransfer -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.smart_contracts.errors import ArgumentSerializationError -from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import \ - SmartContractTransactionsFactory +from multiversx_sdk.smart_contracts.smart_contract_transactions_factory import ( + SmartContractTransactionsFactory, +) class TestSmartContractTransactionsFactory: @@ -28,37 +28,45 @@ def test_create_transaction_for_deploy(self): sender = Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") gas_limit = 6000000 - with pytest.raises(ArgumentSerializationError, match="Unable to encode arguments: unsupported format or missing ABI file"): + with pytest.raises( + ArgumentSerializationError, + match="Unable to encode arguments: unsupported format or missing ABI file", + ): self.factory.create_transaction_for_deploy( sender=sender, bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[1] + arguments=[1], ) transaction_with_typed = self.factory.create_transaction_for_deploy( sender=sender, bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[BigUIntValue(1)] + arguments=[BigUIntValue(1)], ) transaction_abi_aware_with_untyped = self.abi_aware_factory.create_transaction_for_deploy( sender=sender, bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[1] + arguments=[1], ) transaction_abi_aware_with_typed = self.abi_aware_factory.create_transaction_for_deploy( sender=sender, bytecode=self.bytecode, gas_limit=gas_limit, - arguments=[BigUIntValue(1)] + arguments=[BigUIntValue(1)], ) - assert transaction_with_typed.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert transaction_with_typed.receiver.to_bech32() == Address.new_from_hex(CONTRACT_DEPLOY_ADDRESS_HEX).to_bech32() + assert ( + transaction_with_typed.sender.to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) + assert ( + transaction_with_typed.receiver.to_bech32() == Address.new_from_hex(CONTRACT_DEPLOY_ADDRESS_HEX).to_bech32() + ) assert transaction_with_typed.data == f"{self.bytecode.hex()}@0500@0504@01".encode() assert transaction_with_typed.gas_limit == gas_limit assert transaction_with_typed.value == 0 @@ -72,13 +80,16 @@ def test_create_transaction_for_execute_no_transfer(self): function = "add" gas_limit = 6000000 - with pytest.raises(ArgumentSerializationError, match="Unable to encode arguments: unsupported format or missing ABI file"): + with pytest.raises( + ArgumentSerializationError, + match="Unable to encode arguments: unsupported format or missing ABI file", + ): self.factory.create_transaction_for_execute( sender=sender, contract=contract, function=function, gas_limit=gas_limit, - arguments=[7] + arguments=[7], ) transaction_with_typed = self.factory.create_transaction_for_execute( @@ -86,7 +97,7 @@ def test_create_transaction_for_execute_no_transfer(self): contract=contract, function=function, gas_limit=gas_limit, - arguments=[U32Value(7)] + arguments=[U32Value(7)], ) transaction_abi_aware_with_untyped = self.abi_aware_factory.create_transaction_for_execute( @@ -94,7 +105,7 @@ def test_create_transaction_for_execute_no_transfer(self): contract=contract, function=function, gas_limit=gas_limit, - arguments=[7] + arguments=[7], ) transaction_abi_aware_with_typed = self.abi_aware_factory.create_transaction_for_execute( @@ -102,11 +113,17 @@ def test_create_transaction_for_execute_no_transfer(self): contract=contract, function=function, gas_limit=gas_limit, - arguments=[U32Value(7)] + arguments=[U32Value(7)], ) - assert transaction_with_typed.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert transaction_with_typed.receiver.to_bech32() == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4" + assert ( + transaction_with_typed.sender.to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) + assert ( + transaction_with_typed.receiver.to_bech32() + == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4" + ) assert transaction_with_typed.gas_limit == gas_limit assert transaction_with_typed.data assert transaction_with_typed.data.decode() == "add@07" @@ -129,7 +146,7 @@ def test_create_transaction_for_execute_and_tranfer_native_token(self): function=function, gas_limit=gas_limit, arguments=args, - native_transfer_amount=egld_amount + native_transfer_amount=egld_amount, ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -154,7 +171,7 @@ def test_create_transaction_for_execute_and_send_single_esdt(self): function=function, gas_limit=gas_limit, arguments=args, - token_transfers=[transfer] + token_transfers=[transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -183,14 +200,17 @@ def test_create_transaction_for_execute_and_send_multiple_esdts(self): function=function, gas_limit=gas_limit, arguments=args, - token_transfers=[foo_transfer, bar_transfer] + token_transfers=[foo_transfer, bar_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.gas_limit == gas_limit assert transaction.data - assert transaction.data.decode() == "MultiESDTNFTTransfer@00000000000000000500ed8e25a94efa837aae0e593112cfbb01b448755069e1@02@464f4f2d366365313762@@0a@4241522d356263303866@@0c44@64756d6d79@07" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@00000000000000000500ed8e25a94efa837aae0e593112cfbb01b448755069e1@02@464f4f2d366365313762@@0a@4241522d356263303866@@0c44@64756d6d79@07" + ) assert transaction.value == 0 def test_create_transaction_for_execute_and_send_single_nft(self): @@ -208,15 +228,17 @@ def test_create_transaction_for_execute_and_send_single_nft(self): function=function, gas_limit=gas_limit, arguments=args, - token_transfers=[transfer] + token_transfers=[transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.gas_limit == gas_limit assert transaction.data - assert transaction.data.decode( - ) == "ESDTNFTTransfer@4e46542d313233343536@01@01@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@64756d6d79@07" + assert ( + transaction.data.decode() + == "ESDTNFTTransfer@4e46542d313233343536@01@01@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@64756d6d79@07" + ) assert transaction.value == 0 def test_create_transaction_for_execute_and_send_multiple_nfts(self): @@ -237,14 +259,17 @@ def test_create_transaction_for_execute_and_send_multiple_nfts(self): function=function, gas_limit=gas_limit, arguments=args, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.gas_limit == gas_limit assert transaction.data - assert transaction.data.decode() == "MultiESDTNFTTransfer@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@02@4e46542d313233343536@01@01@4e46542d313233343536@2a@01@64756d6d79@07" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@02@4e46542d313233343536@01@01@4e46542d313233343536@2a@01@64756d6d79@07" + ) assert transaction.value == 0 def test_create_transaction_for_execute_and_send_native_and_nfts(self): @@ -266,14 +291,17 @@ def test_create_transaction_for_execute_and_send_native_and_nfts(self): gas_limit=gas_limit, arguments=args, native_transfer_amount=1000000000000000000, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.gas_limit == gas_limit assert transaction.data - assert transaction.data.decode() == "MultiESDTNFTTransfer@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@03@4e46542d313233343536@01@01@4e46542d313233343536@2a@01@45474c442d303030303030@@0de0b6b3a7640000@64756d6d79@07" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@00000000000000000500b9353fe8407f87310c87e12fa1ac807f0485da39d152@03@4e46542d313233343536@01@01@4e46542d313233343536@2a@01@45474c442d303030303030@@0de0b6b3a7640000@64756d6d79@07" + ) assert transaction.value == 0 def test_create_transaction_for_upgrade(self): @@ -282,13 +310,16 @@ def test_create_transaction_for_upgrade(self): contract = self.testdata / "adder.wasm" gas_limit = 6000000 - with pytest.raises(ArgumentSerializationError, match="Unable to encode arguments: unsupported format or missing ABI file"): + with pytest.raises( + ArgumentSerializationError, + match="Unable to encode arguments: unsupported format or missing ABI file", + ): self.factory.create_transaction_for_upgrade( sender=sender, contract=contract_address, bytecode=contract, gas_limit=gas_limit, - arguments=[7] + arguments=[7], ) transaction_with_typed = self.factory.create_transaction_for_upgrade( @@ -296,7 +327,7 @@ def test_create_transaction_for_upgrade(self): contract=contract_address, bytecode=contract, gas_limit=gas_limit, - arguments=[BigUIntValue(7)] + arguments=[BigUIntValue(7)], ) transaction_abi_aware_with_untyped = self.abi_aware_factory.create_transaction_for_upgrade( @@ -304,7 +335,7 @@ def test_create_transaction_for_upgrade(self): contract=contract_address, bytecode=contract, gas_limit=gas_limit, - arguments=[7] + arguments=[7], ) transaction_abi_aware_with_typed = self.abi_aware_factory.create_transaction_for_upgrade( @@ -312,11 +343,17 @@ def test_create_transaction_for_upgrade(self): contract=contract_address, bytecode=contract, gas_limit=gas_limit, - arguments=[BigUIntValue(7)] + arguments=[BigUIntValue(7)], ) - assert transaction_with_typed.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert transaction_with_typed.receiver.to_bech32() == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4" + assert ( + transaction_with_typed.sender.to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) + assert ( + transaction_with_typed.receiver.to_bech32() + == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4" + ) assert transaction_with_typed.data == f"upgradeContract@{self.bytecode.hex()}@0504@07".encode() assert transaction_with_typed.data.decode().startswith("upgradeContract@") assert transaction_with_typed.gas_limit == gas_limit @@ -330,8 +367,7 @@ def test_create_transaction_for_claiming_developer_rewards(self): contract_address = Address.new_from_bech32("erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4") transaction = self.factory.create_transaction_for_claiming_developer_rewards( - sender=sender, - contract=contract_address + sender=sender, contract=contract_address ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -345,12 +381,13 @@ def test_create_transaction_for_changing_owner_address(self): new_owner = Address.from_bech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx") transaction = self.factory.create_transaction_for_changing_owner_address( - sender=sender, - contract=contract_address, - new_owner=new_owner + sender=sender, contract=contract_address, new_owner=new_owner ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqpgqhy6nl6zq07rnzry8uyh6rtyq0uzgtk3e69fqgtz9l4" - assert transaction.data.decode() == "ChangeOwnerAddress@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + assert ( + transaction.data.decode() + == "ChangeOwnerAddress@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + ) assert transaction.gas_limit == 6_000_000 diff --git a/multiversx_sdk/smart_contracts/smart_contract_transactions_factory.py b/multiversx_sdk/smart_contracts/smart_contract_transactions_factory.py index 0014faea..fc20a9d8 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transactions_factory.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transactions_factory.py @@ -7,15 +7,19 @@ from multiversx_sdk.abi.serializer import Serializer from multiversx_sdk.abi.string_value import StringValue from multiversx_sdk.abi.typesystem import is_list_of_typed_values -from multiversx_sdk.builders.token_transfers_data_builder import \ - TokenTransfersDataBuilder +from multiversx_sdk.builders.token_transfers_data_builder import ( + TokenTransfersDataBuilder, +) from multiversx_sdk.builders.transaction_builder import TransactionBuilder -from multiversx_sdk.core import (Address, CodeMetadata, TokenComputer, - TokenTransfer, Transaction) -from multiversx_sdk.core.constants import (CONTRACT_DEPLOY_ADDRESS_HEX, - VM_TYPE_WASM_VM) -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core import ( + Address, + CodeMetadata, + TokenComputer, + TokenTransfer, + Transaction, +) +from multiversx_sdk.core.constants import CONTRACT_DEPLOY_ADDRESS_HEX, VM_TYPE_WASM_VM +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.smart_contracts.errors import ArgumentSerializationError @@ -27,26 +31,30 @@ def __init__(self, config: TransactionsFactoryConfig, abi: Optional[Abi] = None) self.token_computer = TokenComputer() self._data_args_builder = TokenTransfersDataBuilder(self.token_computer) - def create_transaction_for_deploy(self, - sender: Address, - bytecode: Union[Path, bytes], - gas_limit: int, - arguments: Sequence[Any] = [], - native_transfer_amount: int = 0, - is_upgradeable: bool = True, - is_readable: bool = True, - is_payable: bool = False, - is_payable_by_sc: bool = True) -> Transaction: + def create_transaction_for_deploy( + self, + sender: Address, + bytecode: Union[Path, bytes], + gas_limit: int, + arguments: Sequence[Any] = [], + native_transfer_amount: int = 0, + is_upgradeable: bool = True, + is_readable: bool = True, + is_payable: bool = False, + is_payable_by_sc: bool = True, + ) -> Transaction: if isinstance(bytecode, Path): bytecode = bytecode.read_bytes() metadata = CodeMetadata(is_upgradeable, is_readable, is_payable, is_payable_by_sc) - serialized_parts = self.serializer.serialize_to_parts([ - BytesValue(bytecode), - BytesValue(VM_TYPE_WASM_VM), - CodeMetadataValue.new_from_code_metadata(metadata) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + BytesValue(bytecode), + BytesValue(VM_TYPE_WASM_VM), + CodeMetadataValue.new_from_code_metadata(metadata), + ] + ) prepared_arg = self._encode_deploy_arguments(list(arguments)) parts = [arg.hex() for arg in serialized_parts + prepared_arg] @@ -58,17 +66,19 @@ def create_transaction_for_deploy(self, data_parts=parts, gas_limit=gas_limit, add_data_movement_gas=False, - amount=native_transfer_amount + amount=native_transfer_amount, ).build() - def create_transaction_for_execute(self, - sender: Address, - contract: Address, - function: str, - gas_limit: int, - arguments: Sequence[Any] = [], - native_transfer_amount: int = 0, - token_transfers: list[TokenTransfer] = []) -> Transaction: + def create_transaction_for_execute( + self, + sender: Address, + contract: Address, + function: str, + gas_limit: int, + arguments: Sequence[Any] = [], + native_transfer_amount: int = 0, + token_transfers: list[TokenTransfer] = [], + ) -> Transaction: number_of_tokens = len(token_transfers) receiver = contract @@ -88,17 +98,21 @@ def create_transaction_for_execute(self, data_parts = self._data_args_builder.build_args_for_esdt_transfer(transfer=transfer) else: data_parts = self._data_args_builder.build_args_for_single_esdt_nft_transfer( - transfer=transfer, receiver=receiver) + transfer=transfer, receiver=receiver + ) receiver = sender elif number_of_tokens > 1: data_parts = self._data_args_builder.build_args_for_multi_esdt_nft_transfer( - receiver=receiver, transfers=token_transfers) + receiver=receiver, transfers=token_transfers + ) receiver = sender prepared_arguments = self._encode_execute_arguments(function, list(arguments)) - data_parts.append(function) if not data_parts else data_parts.append( - self.serializer.serialize([StringValue(function)]) + ( + data_parts.append(function) + if not data_parts + else data_parts.append(self.serializer.serialize([StringValue(function)])) ) data_parts += [arg.hex() for arg in prepared_arguments] @@ -109,30 +123,31 @@ def create_transaction_for_execute(self, data_parts=data_parts, gas_limit=gas_limit, add_data_movement_gas=False, - amount=native_transfer_amount + amount=native_transfer_amount, ).build() - def create_transaction_for_upgrade(self, - sender: Address, - contract: Address, - bytecode: Union[Path, bytes], - gas_limit: int, - arguments: Sequence[Any] = [], - native_transfer_amount: int = 0, - is_upgradeable: bool = True, - is_readable: bool = True, - is_payable: bool = False, - is_payable_by_sc: bool = True) -> Transaction: + def create_transaction_for_upgrade( + self, + sender: Address, + contract: Address, + bytecode: Union[Path, bytes], + gas_limit: int, + arguments: Sequence[Any] = [], + native_transfer_amount: int = 0, + is_upgradeable: bool = True, + is_readable: bool = True, + is_payable: bool = False, + is_payable_by_sc: bool = True, + ) -> Transaction: if isinstance(bytecode, Path): bytecode = bytecode.read_bytes() metadata = CodeMetadata(is_upgradeable, is_readable, is_payable, is_payable_by_sc) parts = ["upgradeContract"] - serialized_parts = self.serializer.serialize_to_parts([ - BytesValue(bytecode), - CodeMetadataValue.new_from_code_metadata(metadata) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [BytesValue(bytecode), CodeMetadataValue.new_from_code_metadata(metadata)] + ) prepared_arguments = self._encode_upgrade_arguments(list(arguments)) parts += [arg.hex() for arg in serialized_parts + prepared_arguments] @@ -144,12 +159,10 @@ def create_transaction_for_upgrade(self, data_parts=parts, gas_limit=gas_limit, add_data_movement_gas=False, - amount=native_transfer_amount + amount=native_transfer_amount, ).build() - def create_transaction_for_claiming_developer_rewards(self, - sender: Address, - contract: Address) -> Transaction: + def create_transaction_for_claiming_developer_rewards(self, sender: Address, contract: Address) -> Transaction: data_parts = ["ClaimDeveloperRewards"] return TransactionBuilder( @@ -158,13 +171,12 @@ def create_transaction_for_claiming_developer_rewards(self, receiver=contract, data_parts=data_parts, gas_limit=self.config.gas_limit_claim_developer_rewards, - add_data_movement_gas=False + add_data_movement_gas=False, ).build() - def create_transaction_for_changing_owner_address(self, - sender: Address, - contract: Address, - new_owner: Address) -> Transaction: + def create_transaction_for_changing_owner_address( + self, sender: Address, contract: Address, new_owner: Address + ) -> Transaction: data_parts = ["ChangeOwnerAddress", new_owner.to_hex()] return TransactionBuilder( diff --git a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser.py b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser.py index 42138b7b..5971d394 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser.py @@ -2,13 +2,19 @@ from typing import Optional, Union from multiversx_sdk.abi.abi import Abi -from multiversx_sdk.core import (Address, SmartContractResult, - TransactionEvent, TransactionOnNetwork, - find_events_by_identifier) +from multiversx_sdk.core import ( + Address, + SmartContractResult, + TransactionEvent, + TransactionOnNetwork, + find_events_by_identifier, +) from multiversx_sdk.core.constants import ARGS_SEPARATOR from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser_types import ( - DeployedSmartContract, ParsedSmartContractCallOutcome, - SmartContractDeployOutcome) + DeployedSmartContract, + ParsedSmartContractCallOutcome, + SmartContractDeployOutcome, +) class Events(Enum): @@ -20,11 +26,13 @@ class Events(Enum): class SmartContractCallOutcome: """**For internal use only.**""" - def __init__(self, - function: str = "", - return_data_parts: list[bytes] = [], - return_message: str = "", - return_code: str = "") -> None: + def __init__( + self, + function: str = "", + return_data_parts: list[bytes] = [], + return_message: str = "", + return_code: str = "", + ) -> None: self.function = function self.return_data_parts = return_data_parts self.return_message = return_message @@ -41,29 +49,34 @@ def parse_deploy(self, transaction: TransactionOnNetwork) -> SmartContractDeploy contracts = [self._parse_sc_deploy_event(event) for event in events] return SmartContractDeployOutcome( - direct_call_outcome.return_code, direct_call_outcome.return_message, contracts) + direct_call_outcome.return_code, + direct_call_outcome.return_message, + contracts, + ) def parse_execute( - self, transaction: TransactionOnNetwork, function: Optional[str] = None) -> ParsedSmartContractCallOutcome: + self, transaction: TransactionOnNetwork, function: Optional[str] = None + ) -> ParsedSmartContractCallOutcome: direct_call_outcome = self._find_direct_smart_contract_call_outcome(transaction) if self.abi is None: return ParsedSmartContractCallOutcome( values=direct_call_outcome.return_data_parts, return_code=direct_call_outcome.return_code, - return_message=direct_call_outcome.return_message + return_message=direct_call_outcome.return_message, ) function_name = function or direct_call_outcome.function if not function_name: raise Exception( - 'Function name is not available in the transaction, thus endpoint definition (ABI) cannot be picked (for parsing). Please provide the "function" parameter explicitly.') + 'Function name is not available in the transaction, thus endpoint definition (ABI) cannot be picked (for parsing). Please provide the "function" parameter explicitly.' + ) values = self.abi.decode_endpoint_output_parameters(function_name, direct_call_outcome.return_data_parts) return ParsedSmartContractCallOutcome( values=values, return_code=direct_call_outcome.return_code, - return_message=direct_call_outcome.return_message + return_message=direct_call_outcome.return_message, ) def _find_direct_smart_contract_call_outcome(self, transaction: TransactionOnNetwork) -> SmartContractCallOutcome: @@ -82,8 +95,8 @@ def _find_direct_smart_contract_call_outcome(self, transaction: TransactionOnNet return SmartContractCallOutcome(function=transaction.function) def _find_direct_sc_call_outcome_within_sc_results( - self, transaction: TransactionOnNetwork) -> Union[ - SmartContractCallOutcome, None]: + self, transaction: TransactionOnNetwork + ) -> Union[SmartContractCallOutcome, None]: eligible_results: list[SmartContractResult] = [] for result in transaction.smart_contract_results: @@ -91,7 +104,9 @@ def _find_direct_sc_call_outcome_within_sc_results( matches_criteria_on_receiver = result.receiver == transaction.sender matches_criteria_on_previous_hash = result - matches_criteria = matches_criteria_on_data and matches_criteria_on_receiver and matches_criteria_on_previous_hash + matches_criteria = ( + matches_criteria_on_data and matches_criteria_on_receiver and matches_criteria_on_previous_hash + ) if matches_criteria: eligible_results.append(result) @@ -100,7 +115,9 @@ def _find_direct_sc_call_outcome_within_sc_results( return None if len(eligible_results) > 1: - raise Exception(f"More than one smart contract result (holding the return data) found for transaction: {transaction.hash}") + raise Exception( + f"More than one smart contract result (holding the return data) found for transaction: {transaction.hash}" + ) result = eligible_results[0] _, return_code, *return_data_parts = self._string_to_bytes_list(result.data.decode()) @@ -110,10 +127,12 @@ def _find_direct_sc_call_outcome_within_sc_results( function=transaction.function, return_code=return_code, return_message=result.raw.get("returnMessage") or return_code, - return_data_parts=return_data_parts + return_data_parts=return_data_parts, ) - def _find_direct_sc_call_outcome_if_error(self, transaction: TransactionOnNetwork) -> Union[SmartContractCallOutcome, None]: + def _find_direct_sc_call_outcome_if_error( + self, transaction: TransactionOnNetwork + ) -> Union[SmartContractCallOutcome, None]: event_identifier = Events.SignalError.value eligible_events: list[TransactionEvent] = [] @@ -156,8 +175,8 @@ def _find_direct_sc_call_outcome_if_error(self, transaction: TransactionOnNetwor ) def _find_direct_sc_call_outcome_within_write_log_events( - self, transaction: TransactionOnNetwork) -> Union[ - SmartContractCallOutcome, None]: + self, transaction: TransactionOnNetwork + ) -> Union[SmartContractCallOutcome, None]: event_identifier = Events.WriteLog.value eligible_events: list[TransactionEvent] = [] @@ -188,7 +207,7 @@ def _find_direct_sc_call_outcome_within_write_log_events( function=transaction.function, return_code=return_code, return_message=return_code, - return_data_parts=return_data_parts + return_data_parts=return_data_parts, ) def _parse_sc_deploy_event(self, event: TransactionEvent) -> DeployedSmartContract: @@ -200,7 +219,7 @@ def _parse_sc_deploy_event(self, event: TransactionEvent) -> DeployedSmartContra raise Exception("No topic found for owner address") owner_address_topic = event.topics[1] - code_hash_topic = event.topics[2] if event.topics[2] else b'' + code_hash_topic = event.topics[2] if event.topics[2] else b"" contract_address = Address(contract_address_topic) owner_address = Address(owner_address_topic) diff --git a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_devnet_test.py b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_devnet_test.py index 7316c45c..090737e8 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_devnet_test.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_devnet_test.py @@ -1,10 +1,10 @@ import pytest from multiversx_sdk.network_providers.config import NetworkProviderConfig -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider -from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import \ - SmartContractTransactionsOutcomeParser +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider +from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import ( + SmartContractTransactionsOutcomeParser, +) @pytest.mark.networkInteraction diff --git a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_mainnet_test.py b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_mainnet_test.py index 3198d92d..63b2f6c8 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_mainnet_test.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_mainnet_test.py @@ -4,10 +4,10 @@ import pytest from multiversx_sdk.network_providers.config import NetworkProviderConfig -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider -from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import \ - SmartContractTransactionsOutcomeParser +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider +from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import ( + SmartContractTransactionsOutcomeParser, +) @pytest.mark.mainnet diff --git a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_test.py b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_test.py index 7644e027..cbdee974 100644 --- a/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_test.py +++ b/multiversx_sdk/smart_contracts/smart_contract_transactions_outcome_parser_test.py @@ -5,16 +5,20 @@ from multiversx_sdk.abi.abi import Abi from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transaction_on_network import (SmartContractResult, - TransactionEvent, - TransactionLogs) -from multiversx_sdk.network_providers.proxy_network_provider import \ - ProxyNetworkProvider -from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import \ - SmartContractTransactionsOutcomeParser +from multiversx_sdk.core.transaction_on_network import ( + SmartContractResult, + TransactionEvent, + TransactionLogs, +) +from multiversx_sdk.network_providers.proxy_network_provider import ProxyNetworkProvider +from multiversx_sdk.smart_contracts.smart_contract_transactions_outcome_parser import ( + SmartContractTransactionsOutcomeParser, +) from multiversx_sdk.testutils.mock_transaction_on_network import ( - get_empty_smart_contract_result, get_empty_transaction_logs, - get_empty_transaction_on_network) + get_empty_smart_contract_result, + get_empty_transaction_logs, + get_empty_transaction_on_network, +) class TestSmartContractTransactionsOutcomeParser: @@ -31,7 +35,7 @@ def test_parse_minimalistic_deploy_outcome(self): identifier="SCDeploy", topics=[contract.get_public_key(), deployer.get_public_key(), code_hash], data=b"", - additional_data=[] + additional_data=[], ) transaction = get_empty_transaction_on_network() @@ -52,13 +56,9 @@ def test_parse_deploy_outcome(self): 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=[] + additional_data=[], ) logs = TransactionLogs(address=Address.empty(), events=[event]) @@ -67,7 +67,7 @@ def test_parse_deploy_outcome(self): sender=Address.empty(), receiver=Address.empty(), data="@6f6b".encode(), - logs=get_empty_transaction_logs() + logs=get_empty_transaction_logs(), ) tx_on_network = get_empty_transaction_on_network() @@ -91,12 +91,9 @@ def test_parse_deploy_outcome_with_error(self): raw={}, address=Address.empty(), identifier="signalError", - topics=[ - deployer.get_public_key(), - b"wrong number of arguments" - ], + topics=[deployer.get_public_key(), b"wrong number of arguments"], data="@75736572206572726f72".encode(), - additional_data=[] + additional_data=[], ) logs = TransactionLogs(address=Address.empty(), events=[event]) @@ -139,7 +136,12 @@ def test_parse_execute_without_function_name(self): 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.')): + 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) @pytest.mark.networkInteraction @@ -150,10 +152,13 @@ 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/testutils/mock_network_provider.py b/multiversx_sdk/testutils/mock_network_provider.py index 5b930980..8fa9d6ca 100644 --- a/multiversx_sdk/testutils/mock_network_provider.py +++ b/multiversx_sdk/testutils/mock_network_provider.py @@ -5,16 +5,20 @@ from multiversx_sdk.core.address import Address 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_on_network import ( + SmartContractResult, + TransactionLogs, + TransactionOnNetwork, +) from multiversx_sdk.core.transaction_status import TransactionStatus -from multiversx_sdk.network_providers.resources import (AccountOnNetwork, - AwaitingOptions) +from multiversx_sdk.network_providers.resources import AccountOnNetwork, AwaitingOptions from multiversx_sdk.smart_contracts.smart_contract_query import ( - SmartContractQuery, SmartContractQueryResponse) -from multiversx_sdk.testutils.mock_transaction_on_network import \ - get_empty_transaction_on_network + SmartContractQuery, + SmartContractQueryResponse, +) +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_transaction_on_network, +) from multiversx_sdk.testutils.utils import create_account_egld_balance @@ -31,7 +35,7 @@ def __init__(self) -> None: address=MockNetworkProvider.alice, nonce=0, balance=create_account_egld_balance(1000), - is_guarded=False + is_guarded=False, ) bob_account = AccountOnNetwork( @@ -39,7 +43,7 @@ def __init__(self) -> None: address=MockNetworkProvider.bob, nonce=5, balance=create_account_egld_balance(500), - is_guarded=False + is_guarded=False, ) carol_account = AccountOnNetwork( @@ -47,13 +51,13 @@ def __init__(self) -> None: address=MockNetworkProvider.carol, nonce=42, balance=create_account_egld_balance(300), - is_guarded=False + is_guarded=False, ) self.accounts: dict[str, AccountOnNetwork] = { MockNetworkProvider.alice.to_bech32(): alice_account, MockNetworkProvider.bob.to_bech32(): bob_account, - MockNetworkProvider.carol.to_bech32(): carol_account + MockNetworkProvider.carol.to_bech32(): carol_account, } self.query_contract_responders: list[QueryContractResponder] = [] self.get_transaction_responders: list[GetTransactionResponder] = [] @@ -92,7 +96,7 @@ def predicate(hash: str) -> bool: sender=Address.empty(), receiver=Address.empty(), data=return_code_and_data.encode(), - logs=TransactionLogs(address=Address.empty(), events=[]) + logs=TransactionLogs(address=Address.empty(), events=[]), ) ] @@ -107,12 +111,14 @@ def mock_transaction_timeline_by_hash(self, hash: str, timeline_points: list[Any def fn(): for point in timeline_points: if isinstance(point, TransactionStatus): + def set_tx_status(transaction: TransactionOnNetwork): transaction.status = point self.mock_update_transaction(hash, set_tx_status) elif isinstance(point, TimelinePointMarkCompleted): + def mark_tx_as_completed(transaction: TransactionOnNetwork): transaction.status.is_completed = True @@ -128,6 +134,7 @@ def mock_account_balance_timeline_by_address(self, address: Address, timeline_po def fn(): for point in timeline_points: if isinstance(point, TimelinePointMarkCompleted): + def mark_account_condition_reached(account: AccountOnNetwork): account.balance = account.balance + create_account_egld_balance(7) @@ -172,12 +179,19 @@ def query_contract(self, query: SmartContractQuery) -> SmartContractQueryRespons raise Exception("No query response to return") - def await_transaction_completed(self, transaction_hash: Union[str, bytes], options: Optional[AwaitingOptions] = None) -> TransactionOnNetwork: - ... + def await_transaction_completed( + self, + transaction_hash: Union[str, bytes], + options: Optional[AwaitingOptions] = None, + ) -> TransactionOnNetwork: ... class QueryContractResponder: - def __init__(self, matches: Callable[[SmartContractQuery], bool], response: SmartContractQueryResponse) -> None: + def __init__( + self, + matches: Callable[[SmartContractQuery], bool], + response: SmartContractQueryResponse, + ) -> None: self.matches = matches self.response = response diff --git a/multiversx_sdk/testutils/mock_transaction_on_network.py b/multiversx_sdk/testutils/mock_transaction_on_network.py index f319c631..f84e1fa9 100644 --- a/multiversx_sdk/testutils/mock_transaction_on_network.py +++ b/multiversx_sdk/testutils/mock_transaction_on_network.py @@ -1,7 +1,9 @@ from multiversx_sdk.core.address import Address -from multiversx_sdk.core.transaction_on_network import (SmartContractResult, - TransactionLogs, - TransactionOnNetwork) +from multiversx_sdk.core.transaction_on_network import ( + SmartContractResult, + TransactionLogs, + TransactionOnNetwork, +) from multiversx_sdk.core.transaction_status import TransactionStatus @@ -33,7 +35,7 @@ def get_empty_transaction_on_network() -> TransactionOnNetwork: signature=b"", status=TransactionStatus(""), smart_contract_results=[get_empty_smart_contract_result()], - logs=get_empty_transaction_logs() + logs=get_empty_transaction_logs(), ) @@ -47,7 +49,7 @@ def get_empty_smart_contract_result() -> SmartContractResult: sender=Address.empty(), receiver=Address.empty(), data=b"", - logs=get_empty_transaction_logs() + logs=get_empty_transaction_logs(), ) diff --git a/multiversx_sdk/token_management/__init__.py b/multiversx_sdk/token_management/__init__.py index e1c2e8e3..73f10e11 100644 --- a/multiversx_sdk/token_management/__init__.py +++ b/multiversx_sdk/token_management/__init__.py @@ -1,21 +1,53 @@ -from multiversx_sdk.token_management.token_management_controller import \ - TokenManagementController +from multiversx_sdk.token_management.token_management_controller import ( + TokenManagementController, +) from multiversx_sdk.token_management.token_management_transactions_factory import ( - TokenManagementTransactionsFactory, TokenType) -from multiversx_sdk.token_management.token_management_transactions_outcome_parser import \ - TokenManagementTransactionsOutcomeParser + TokenManagementTransactionsFactory, + TokenType, +) +from multiversx_sdk.token_management.token_management_transactions_outcome_parser import ( + TokenManagementTransactionsOutcomeParser, +) from multiversx_sdk.token_management.token_management_transactions_outcome_parser_types import ( - AddQuantityOutcome, BurnOutcome, BurnQuantityOutcome, FreezeOutcome, - IssueFungibleOutcome, IssueNonFungibleOutcome, IssueSemiFungibleOutcome, - MintOutcome, NFTCreateOutcome, PauseOutcome, RegisterAndSetAllRolesOutcome, - RegisterMetaEsdtOutcome, SetSpecialRoleOutcome, UnFreezeOutcome, - UnPauseOutcome, UpdateAttributesOutcome, WipeOutcome) + AddQuantityOutcome, + BurnOutcome, + BurnQuantityOutcome, + FreezeOutcome, + IssueFungibleOutcome, + IssueNonFungibleOutcome, + IssueSemiFungibleOutcome, + MintOutcome, + NFTCreateOutcome, + PauseOutcome, + RegisterAndSetAllRolesOutcome, + RegisterMetaEsdtOutcome, + SetSpecialRoleOutcome, + UnFreezeOutcome, + UnPauseOutcome, + UpdateAttributesOutcome, + WipeOutcome, +) __all__ = [ - "TokenManagementTransactionsFactory", "TokenType", "TokenManagementTransactionsOutcomeParser", - "TokenManagementController", "AddQuantityOutcome", "BurnOutcome", "BurnQuantityOutcome", "FreezeOutcome", - "IssueFungibleOutcome", "IssueNonFungibleOutcome", "IssueSemiFungibleOutcome", - "MintOutcome", "NFTCreateOutcome", "PauseOutcome", "RegisterAndSetAllRolesOutcome", - "RegisterMetaEsdtOutcome", "SetSpecialRoleOutcome", "UnFreezeOutcome", - "UnPauseOutcome", "UpdateAttributesOutcome", "WipeOutcome" + "TokenManagementTransactionsFactory", + "TokenType", + "TokenManagementTransactionsOutcomeParser", + "TokenManagementController", + "AddQuantityOutcome", + "BurnOutcome", + "BurnQuantityOutcome", + "FreezeOutcome", + "IssueFungibleOutcome", + "IssueNonFungibleOutcome", + "IssueSemiFungibleOutcome", + "MintOutcome", + "NFTCreateOutcome", + "PauseOutcome", + "RegisterAndSetAllRolesOutcome", + "RegisterMetaEsdtOutcome", + "SetSpecialRoleOutcome", + "UnFreezeOutcome", + "UnPauseOutcome", + "UpdateAttributesOutcome", + "WipeOutcome", ] diff --git a/multiversx_sdk/token_management/token_management_controller.py b/multiversx_sdk/token_management/token_management_controller.py index d5c4286f..f21fd147 100644 --- a/multiversx_sdk/token_management/token_management_controller.py +++ b/multiversx_sdk/token_management/token_management_controller.py @@ -762,7 +762,9 @@ def create_transaction_for_local_minting( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_local_minting( - sender=sender.address, token_identifier=token_identifier, supply_to_mint=supply_to_mint + sender=sender.address, + token_identifier=token_identifier, + supply_to_mint=supply_to_mint, ) transaction.guardian = guardian @@ -791,7 +793,9 @@ def create_transaction_for_local_burning( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_local_burning( - sender=sender.address, token_identifier=token_identifier, supply_to_burn=supply_to_burn + sender=sender.address, + token_identifier=token_identifier, + supply_to_burn=supply_to_burn, ) transaction.guardian = guardian @@ -919,7 +923,9 @@ def create_transaction_for_transferring_ownership( relayer: Optional[Address] = None, ) -> Transaction: transaction = self.factory.create_transaction_for_transferring_ownership( - sender=sender.address, token_identifier=token_identifier, new_owner=new_owner + sender=sender.address, + token_identifier=token_identifier, + new_owner=new_owner, ) transaction.guardian = guardian diff --git a/multiversx_sdk/token_management/token_management_transactions_factory.py b/multiversx_sdk/token_management/token_management_transactions_factory.py index ebde6fb6..1ed148a1 100644 --- a/multiversx_sdk/token_management/token_management_transactions_factory.py +++ b/multiversx_sdk/token_management/token_management_transactions_factory.py @@ -9,8 +9,7 @@ from multiversx_sdk.builders.transaction_builder import TransactionBuilder from multiversx_sdk.core import Address, Transaction from multiversx_sdk.core.errors import BadUsageError -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig logger = logging.getLogger(__name__) @@ -39,24 +38,34 @@ def create_transaction_for_issuing_fungible( can_pause: bool, can_change_owner: bool, can_upgrade: bool, - can_add_special_roles: bool + can_add_special_roles: bool, ) -> Transaction: self._notify_about_unsetting_burn_role_globally() - parts = ["issue",] - - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - BigUIntValue(initial_supply), - BigUIntValue(num_decimals), - *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], - *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], - *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], - *[StringValue("canChangeOwner"), self._bool_to_typed_string(can_change_owner)], - *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], - *[StringValue("canAddSpecialRoles"), self._bool_to_typed_string(can_add_special_roles)] - ]) + parts = [ + "issue", + ] + + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + BigUIntValue(initial_supply), + BigUIntValue(num_decimals), + *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], + *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], + *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], + *[ + StringValue("canChangeOwner"), + self._bool_to_typed_string(can_change_owner), + ], + *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], + *[ + StringValue("canAddSpecialRoles"), + self._bool_to_typed_string(can_add_special_roles), + ], + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -67,16 +76,18 @@ def create_transaction_for_issuing_fungible( amount=self._config.issue_cost, gas_limit=self._config.gas_limit_issue, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def _notify_about_unsetting_burn_role_globally(self) -> None: - logger.info(""" + logger.info( + """ ========== IMPORTANT! ========== You are about to issue (register) a new token. This will set the role "ESDTRoleBurnForAll" (globally). -Once the token is registered, you can unset this role by calling "unsetBurnRoleGlobally" (in a separate transaction).""") +Once the token is registered, you can unset this role by calling "unsetBurnRoleGlobally" (in a separate transaction).""" + ) def create_transaction_for_issuing_semi_fungible( self, @@ -89,23 +100,34 @@ def create_transaction_for_issuing_semi_fungible( can_transfer_nft_create_role: bool, can_change_owner: bool, can_upgrade: bool, - can_add_special_roles: bool + can_add_special_roles: bool, ) -> Transaction: self._notify_about_unsetting_burn_role_globally() parts = ["issueSemiFungible"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], - *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], - *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], - *[StringValue("canTransferNFTCreateRole"), self._bool_to_typed_string(can_transfer_nft_create_role)], - *[StringValue("canChangeOwner"), self._bool_to_typed_string(can_change_owner)], - *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], - *[StringValue("canAddSpecialRoles"), self._bool_to_typed_string(can_add_special_roles)] - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], + *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], + *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], + *[ + StringValue("canTransferNFTCreateRole"), + self._bool_to_typed_string(can_transfer_nft_create_role), + ], + *[ + StringValue("canChangeOwner"), + self._bool_to_typed_string(can_change_owner), + ], + *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], + *[ + StringValue("canAddSpecialRoles"), + self._bool_to_typed_string(can_add_special_roles), + ], + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -116,7 +138,7 @@ def create_transaction_for_issuing_semi_fungible( amount=self._config.issue_cost, gas_limit=self._config.gas_limit_issue, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_issuing_non_fungible( @@ -130,23 +152,34 @@ def create_transaction_for_issuing_non_fungible( can_transfer_nft_create_role: bool, can_change_owner: bool, can_upgrade: bool, - can_add_special_roles: bool + can_add_special_roles: bool, ) -> Transaction: self._notify_about_unsetting_burn_role_globally() parts = ["issueNonFungible"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], - *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], - *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], - *[StringValue("canTransferNFTCreateRole"), self._bool_to_typed_string(can_transfer_nft_create_role)], - *[StringValue("canChangeOwner"), self._bool_to_typed_string(can_change_owner)], - *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], - *[StringValue("canAddSpecialRoles"), self._bool_to_typed_string(can_add_special_roles)] - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], + *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], + *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], + *[ + StringValue("canTransferNFTCreateRole"), + self._bool_to_typed_string(can_transfer_nft_create_role), + ], + *[ + StringValue("canChangeOwner"), + self._bool_to_typed_string(can_change_owner), + ], + *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], + *[ + StringValue("canAddSpecialRoles"), + self._bool_to_typed_string(can_add_special_roles), + ], + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -157,7 +190,7 @@ def create_transaction_for_issuing_non_fungible( amount=self._config.issue_cost, gas_limit=self._config.gas_limit_issue, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_registering_meta_esdt( @@ -172,24 +205,35 @@ def create_transaction_for_registering_meta_esdt( can_transfer_nft_create_role: bool, can_change_owner: bool, can_upgrade: bool, - can_add_special_roles: bool + can_add_special_roles: bool, ) -> Transaction: self._notify_about_unsetting_burn_role_globally() parts = ["registerMetaESDT"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - BigUIntValue(num_decimals), - *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], - *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], - *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], - *[StringValue("canTransferNFTCreateRole"), self._bool_to_typed_string(can_transfer_nft_create_role)], - *[StringValue("canChangeOwner"), self._bool_to_typed_string(can_change_owner)], - *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], - *[StringValue("canAddSpecialRoles"), self._bool_to_typed_string(can_add_special_roles)] - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + BigUIntValue(num_decimals), + *[StringValue("canFreeze"), self._bool_to_typed_string(can_freeze)], + *[StringValue("canWipe"), self._bool_to_typed_string(can_wipe)], + *[StringValue("canPause"), self._bool_to_typed_string(can_pause)], + *[ + StringValue("canTransferNFTCreateRole"), + self._bool_to_typed_string(can_transfer_nft_create_role), + ], + *[ + StringValue("canChangeOwner"), + self._bool_to_typed_string(can_change_owner), + ], + *[StringValue("canUpgrade"), self._bool_to_typed_string(can_upgrade)], + *[ + StringValue("canAddSpecialRoles"), + self._bool_to_typed_string(can_add_special_roles), + ], + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -209,18 +253,20 @@ def create_transaction_for_registering_and_setting_roles( token_name: str, token_ticker: str, token_type: TokenType, - num_decimals: int + num_decimals: int, ) -> Transaction: self._notify_about_unsetting_burn_role_globally() parts = ["registerAndSetAllRoles"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - StringValue(token_type.value), - BigUIntValue(num_decimals) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + StringValue(token_type.value), + BigUIntValue(num_decimals), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -231,17 +277,13 @@ def create_transaction_for_registering_and_setting_roles( amount=self._config.issue_cost, gas_limit=self._config.gas_limit_issue, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_setting_burn_role_globally( - self, - sender: Address, - token_identifier: str - ) -> Transaction: + def create_transaction_for_setting_burn_role_globally(self, sender: Address, token_identifier: str) -> Transaction: parts = [ "setBurnRoleGlobally", - self.serializer.serialize([StringValue(token_identifier)]) + self.serializer.serialize([StringValue(token_identifier)]), ] return TransactionBuilder( @@ -251,17 +293,15 @@ def create_transaction_for_setting_burn_role_globally( amount=None, gas_limit=self._config.gas_limit_toggle_burn_role_globally, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_unsetting_burn_role_globally( - self, - sender: Address, - token_identifier: str + self, sender: Address, token_identifier: str ) -> Transaction: parts = [ "unsetBurnRoleGlobally", - self.serializer.serialize([StringValue(token_identifier)]) + self.serializer.serialize([StringValue(token_identifier)]), ] return TransactionBuilder( @@ -271,7 +311,7 @@ def create_transaction_for_unsetting_burn_role_globally( amount=None, gas_limit=self._config.gas_limit_toggle_burn_role_globally, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_setting_special_role_on_fungible_token( @@ -281,7 +321,7 @@ def create_transaction_for_setting_special_role_on_fungible_token( token_identifier: str, add_role_local_mint: bool = False, add_role_local_burn: bool = False, - add_role_esdt_transfer_role: bool = False + add_role_esdt_transfer_role: bool = False, ) -> Transaction: parts = [ "setSpecialRole", @@ -289,11 +329,13 @@ def create_transaction_for_setting_special_role_on_fungible_token( user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleLocalMint")] if add_role_local_mint else []), - *([StringValue("ESDTRoleLocalBurn")] if add_role_local_burn else []), - *([StringValue("ESDTTransferRole")]if add_role_esdt_transfer_role else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleLocalMint")] if add_role_local_mint else []), + *([StringValue("ESDTRoleLocalBurn")] if add_role_local_burn else []), + *([StringValue("ESDTTransferRole")] if add_role_esdt_transfer_role else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -304,7 +346,7 @@ def create_transaction_for_setting_special_role_on_fungible_token( amount=None, gas_limit=self._config.gas_limit_set_special_role, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_unsetting_special_role_on_fungible_token( @@ -314,19 +356,21 @@ def create_transaction_for_unsetting_special_role_on_fungible_token( token_identifier: str, remove_role_local_mint: bool = False, remove_role_local_burn: bool = False, - remove_role_esdt_transfer_role: bool = False + remove_role_esdt_transfer_role: bool = False, ) -> Transaction: parts = [ "unSetSpecialRole", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleLocalMint")] if remove_role_local_mint else []), - *([StringValue("ESDTRoleLocalBurn")] if remove_role_local_burn else []), - *([StringValue("ESDTTransferRole")]if remove_role_esdt_transfer_role else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleLocalMint")] if remove_role_local_mint else []), + *([StringValue("ESDTRoleLocalBurn")] if remove_role_local_burn else []), + *([StringValue("ESDTTransferRole")] if remove_role_esdt_transfer_role else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -337,7 +381,7 @@ def create_transaction_for_unsetting_special_role_on_fungible_token( amount=None, gas_limit=self._config.gas_limit_set_special_role, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_setting_special_role_on_semi_fungible_token( @@ -358,20 +402,22 @@ def create_transaction_for_setting_special_role_on_semi_fungible_token( parts = [ "setSpecialRole", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleNFTCreate")] if add_role_nft_create else []), - *([StringValue("ESDTRoleNFTBurn")] if add_role_nft_burn else []), - *([StringValue("ESDTRoleNFTAddQuantity")]if add_role_nft_add_quantity else []), - *([StringValue("ESDTTransferRole")] if add_role_esdt_transfer_role else []), - *([StringValue("ESDTRoleNFTUpdate")] if add_role_nft_update else []), - *([StringValue("ESDTRoleModifyRoyalties")]if add_role_esdt_modify_royalties else []), - *([StringValue("ESDTRoleSetNewURI")] if add_role_esdt_set_new_uri else []), - *([StringValue("ESDTRoleModifyCreator")] if add_role_esdt_modify_creator else []), - *([StringValue("ESDTRoleNFTRecreate")]if add_role_nft_recreate else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleNFTCreate")] if add_role_nft_create else []), + *([StringValue("ESDTRoleNFTBurn")] if add_role_nft_burn else []), + *([StringValue("ESDTRoleNFTAddQuantity")] if add_role_nft_add_quantity else []), + *([StringValue("ESDTTransferRole")] if add_role_esdt_transfer_role else []), + *([StringValue("ESDTRoleNFTUpdate")] if add_role_nft_update else []), + *([StringValue("ESDTRoleModifyRoyalties")] if add_role_esdt_modify_royalties else []), + *([StringValue("ESDTRoleSetNewURI")] if add_role_esdt_set_new_uri else []), + *([StringValue("ESDTRoleModifyCreator")] if add_role_esdt_modify_creator else []), + *([StringValue("ESDTRoleNFTRecreate")] if add_role_nft_recreate else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -382,7 +428,7 @@ def create_transaction_for_setting_special_role_on_semi_fungible_token( amount=None, gas_limit=self._config.gas_limit_set_special_role, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_unsetting_special_role_on_semi_fungible_token( @@ -402,19 +448,21 @@ def create_transaction_for_unsetting_special_role_on_semi_fungible_token( parts = [ "unSetSpecialRole", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleNFTBurn")] if remove_role_nft_burn else []), - *([StringValue("ESDTRoleNFTAddQuantity")]if remove_role_nft_add_quantity else []), - *([StringValue("ESDTTransferRole")] if remove_role_esdt_transfer_role else []), - *([StringValue("ESDTRoleNFTUpdate")] if remove_role_nft_update else []), - *([StringValue("ESDTRoleModifyRoyalties")]if remove_role_esdt_modify_royalties else []), - *([StringValue("ESDTRoleSetNewURI")] if remove_role_esdt_set_new_uri else []), - *([StringValue("ESDTRoleModifyCreator")] if remove_role_esdt_modify_creator else []), - *([StringValue("ESDTRoleNFTRecreate")] if remove_role_nft_recreate else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleNFTBurn")] if remove_role_nft_burn else []), + *([StringValue("ESDTRoleNFTAddQuantity")] if remove_role_nft_add_quantity else []), + *([StringValue("ESDTTransferRole")] if remove_role_esdt_transfer_role else []), + *([StringValue("ESDTRoleNFTUpdate")] if remove_role_nft_update else []), + *([StringValue("ESDTRoleModifyRoyalties")] if remove_role_esdt_modify_royalties else []), + *([StringValue("ESDTRoleSetNewURI")] if remove_role_esdt_set_new_uri else []), + *([StringValue("ESDTRoleModifyCreator")] if remove_role_esdt_modify_creator else []), + *([StringValue("ESDTRoleNFTRecreate")] if remove_role_nft_recreate else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -425,7 +473,7 @@ def create_transaction_for_unsetting_special_role_on_semi_fungible_token( amount=None, gas_limit=self._config.gas_limit_set_special_role, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_setting_special_role_on_non_fungible_token( @@ -447,21 +495,23 @@ def create_transaction_for_setting_special_role_on_non_fungible_token( parts = [ "setSpecialRole", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleNFTCreate")] if add_role_nft_create else []), - *([StringValue("ESDTRoleNFTBurn")]if add_role_nft_burn else []), - *([StringValue("ESDTRoleNFTUpdateAttributes")] if add_role_nft_update_attributes else []), - *([StringValue("ESDTRoleNFTAddURI")] if add_role_nft_add_uri else []), - *([StringValue("ESDTTransferRole")]if add_role_esdt_transfer_role else []), - *([StringValue("ESDTRoleNFTUpdate")] if add_role_nft_update else []), - *([StringValue("ESDTRoleModifyRoyalties")] if add_role_esdt_modify_royalties else []), - *([StringValue("ESDTRoleSetNewURI")] if add_role_esdt_set_new_uri else []), - *([StringValue("ESDTRoleModifyCreator")] if add_role_esdt_modify_creator else []), - *([StringValue("ESDTRoleNFTRecreate")] if add_role_nft_recreate else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleNFTCreate")] if add_role_nft_create else []), + *([StringValue("ESDTRoleNFTBurn")] if add_role_nft_burn else []), + *([StringValue("ESDTRoleNFTUpdateAttributes")] if add_role_nft_update_attributes else []), + *([StringValue("ESDTRoleNFTAddURI")] if add_role_nft_add_uri else []), + *([StringValue("ESDTTransferRole")] if add_role_esdt_transfer_role else []), + *([StringValue("ESDTRoleNFTUpdate")] if add_role_nft_update else []), + *([StringValue("ESDTRoleModifyRoyalties")] if add_role_esdt_modify_royalties else []), + *([StringValue("ESDTRoleSetNewURI")] if add_role_esdt_set_new_uri else []), + *([StringValue("ESDTRoleModifyCreator")] if add_role_esdt_modify_creator else []), + *([StringValue("ESDTRoleNFTRecreate")] if add_role_nft_recreate else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -493,20 +543,22 @@ def create_transaction_for_unsetting_special_role_on_non_fungible_token( parts = [ "unSetSpecialRole", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] - serialized_parts = self.serializer.serialize_to_parts([ - *([StringValue("ESDTRoleNFTBurn")]if remove_role_nft_burn else []), - *([StringValue("ESDTRoleNFTUpdateAttributes")] if remove_role_nft_update_attributes else []), - *([StringValue("ESDTRoleNFTAddURI")] if remove_role_nft_remove_uri else []), - *([StringValue("ESDTTransferRole")]if remove_role_esdt_transfer_role else []), - *([StringValue("ESDTRoleNFTUpdate")] if remove_role_nft_update else []), - *([StringValue("ESDTRoleModifyRoyalties")] if remove_role_esdt_modify_royalties else []), - *([StringValue("ESDTRoleSetNewURI")] if remove_role_esdt_set_new_uri else []), - *([StringValue("ESDTRoleModifyCreator")] if remove_role_esdt_modify_creator else []), - *([StringValue("ESDTRoleNFTRecreate")] if remove_role_nft_recreate else []) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + *([StringValue("ESDTRoleNFTBurn")] if remove_role_nft_burn else []), + *([StringValue("ESDTRoleNFTUpdateAttributes")] if remove_role_nft_update_attributes else []), + *([StringValue("ESDTRoleNFTAddURI")] if remove_role_nft_remove_uri else []), + *([StringValue("ESDTTransferRole")] if remove_role_esdt_transfer_role else []), + *([StringValue("ESDTRoleNFTUpdate")] if remove_role_nft_update else []), + *([StringValue("ESDTRoleModifyRoyalties")] if remove_role_esdt_modify_royalties else []), + *([StringValue("ESDTRoleSetNewURI")] if remove_role_esdt_set_new_uri else []), + *([StringValue("ESDTRoleModifyCreator")] if remove_role_esdt_modify_creator else []), + *([StringValue("ESDTRoleNFTRecreate")] if remove_role_nft_recreate else []), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -529,22 +581,24 @@ def create_transaction_for_creating_nft( royalties: int, hash: str, attributes: bytes, - uris: list[str] + uris: list[str], ) -> Transaction: if not uris: raise BadUsageError("No URIs provided") parts = ["ESDTNFTCreate"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(initial_quantity), - StringValue(name), - BigUIntValue(royalties), - StringValue(hash), - BytesValue(attributes), - *map(StringValue, uris) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(initial_quantity), + StringValue(name), + BigUIntValue(royalties), + StringValue(hash), + BytesValue(attributes), + *map(StringValue, uris), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -559,18 +613,11 @@ def create_transaction_for_creating_nft( amount=None, gas_limit=self._config.gas_limit_esdt_nft_create + storage_gas_limit, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_pausing( - self, - sender: Address, - token_identifier: str - ) -> Transaction: - parts = [ - "pause", - self.serializer.serialize([StringValue(token_identifier)]) - ] + def create_transaction_for_pausing(self, sender: Address, token_identifier: str) -> Transaction: + parts = ["pause", self.serializer.serialize([StringValue(token_identifier)])] return TransactionBuilder( config=self._config, @@ -579,18 +626,11 @@ def create_transaction_for_pausing( amount=None, gas_limit=self._config.gas_limit_pausing, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_unpausing( - self, - sender: Address, - token_identifier: str - ) -> Transaction: - parts = [ - "unPause", - self.serializer.serialize([StringValue(token_identifier)]) - ] + def create_transaction_for_unpausing(self, sender: Address, token_identifier: str) -> Transaction: + parts = ["unPause", self.serializer.serialize([StringValue(token_identifier)])] return TransactionBuilder( config=self._config, @@ -599,20 +639,15 @@ def create_transaction_for_unpausing( amount=None, gas_limit=self._config.gas_limit_pausing, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_freezing( - self, - sender: Address, - user: Address, - token_identifier: str - ) -> Transaction: + def create_transaction_for_freezing(self, sender: Address, user: Address, token_identifier: str) -> Transaction: """Can be used for FungibleESDT""" parts = [ "freeze", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -625,17 +660,12 @@ def create_transaction_for_freezing( data_parts=parts, ).build() - def create_transaction_for_unfreezing( - self, - sender: Address, - user: Address, - token_identifier: str - ) -> Transaction: + def create_transaction_for_unfreezing(self, sender: Address, user: Address, token_identifier: str) -> Transaction: """Can be used for FungibleESDT""" parts = [ "unFreeze", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -645,19 +675,14 @@ def create_transaction_for_unfreezing( amount=None, gas_limit=self._config.gas_limit_freezing, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_wiping( - self, - sender: Address, - user: Address, - token_identifier: str - ) -> Transaction: + def create_transaction_for_wiping(self, sender: Address, user: Address, token_identifier: str) -> Transaction: parts = [ "wipe", self.serializer.serialize([StringValue(token_identifier)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -667,19 +692,16 @@ def create_transaction_for_wiping( amount=None, gas_limit=self._config.gas_limit_wiping, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_local_minting( - self, - sender: Address, - token_identifier: str, - supply_to_mint: int + self, sender: Address, token_identifier: str, supply_to_mint: int ) -> Transaction: parts = [ "ESDTLocalMint", self.serializer.serialize([StringValue(token_identifier)]), - self.serializer.serialize([BigUIntValue(supply_to_mint)]) + self.serializer.serialize([BigUIntValue(supply_to_mint)]), ] return TransactionBuilder( @@ -689,19 +711,16 @@ def create_transaction_for_local_minting( amount=None, gas_limit=self._config.gas_limit_esdt_local_mint, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_local_burning( - self, - sender: Address, - token_identifier: str, - supply_to_burn: int + self, sender: Address, token_identifier: str, supply_to_burn: int ) -> Transaction: parts = [ "ESDTLocalBurn", self.serializer.serialize([StringValue(token_identifier)]), - self.serializer.serialize([BigUIntValue(supply_to_burn)]) + self.serializer.serialize([BigUIntValue(supply_to_burn)]), ] return TransactionBuilder( @@ -711,7 +730,7 @@ def create_transaction_for_local_burning( amount=None, gas_limit=self._config.gas_limit_esdt_local_burn, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_updating_attributes( @@ -719,15 +738,17 @@ def create_transaction_for_updating_attributes( sender: Address, token_identifier: str, token_nonce: int, - attributes: bytes + attributes: bytes, ) -> Transaction: parts = ["ESDTNFTUpdateAttributes"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - BytesValue(attributes) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + BytesValue(attributes), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -738,7 +759,7 @@ def create_transaction_for_updating_attributes( amount=None, gas_limit=self._config.gas_limit_esdt_nft_update_attributes, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_adding_quantity( @@ -746,15 +767,17 @@ def create_transaction_for_adding_quantity( sender: Address, token_identifier: str, token_nonce: int, - quantity_to_add: int + quantity_to_add: int, ) -> Transaction: parts = ["ESDTNFTAddQuantity"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - BigUIntValue(quantity_to_add) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + BigUIntValue(quantity_to_add), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -765,7 +788,7 @@ def create_transaction_for_adding_quantity( amount=None, gas_limit=self._config.gas_limit_esdt_nft_add_quantity, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def create_transaction_for_burning_quantity( @@ -773,15 +796,17 @@ def create_transaction_for_burning_quantity( sender: Address, token_identifier: str, token_nonce: int, - quantity_to_burn: int + quantity_to_burn: int, ) -> Transaction: parts = ["ESDTNFTBurn"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - BigUIntValue(quantity_to_burn) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + BigUIntValue(quantity_to_burn), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -792,21 +817,25 @@ def create_transaction_for_burning_quantity( amount=None, gas_limit=self._config.gas_limit_esdt_nft_burn, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_modifying_royalties(self, - sender: Address, - token_identifier: str, - token_nonce: int, - new_royalties: int) -> Transaction: + def create_transaction_for_modifying_royalties( + self, + sender: Address, + token_identifier: str, + token_nonce: int, + new_royalties: int, + ) -> Transaction: parts = ["ESDTModifyRoyalties"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - BigUIntValue(new_royalties) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + BigUIntValue(new_royalties), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -817,24 +846,28 @@ def create_transaction_for_modifying_royalties(self, amount=None, gas_limit=self._config.gas_limit_esdt_modify_royalties, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_setting_new_uris(self, - sender: Address, - token_identifier: str, - token_nonce: int, - new_uris: list[str]) -> Transaction: + def create_transaction_for_setting_new_uris( + self, + sender: Address, + token_identifier: str, + token_nonce: int, + new_uris: list[str], + ) -> Transaction: if not new_uris: raise BadUsageError("No URIs provided") parts = ["ESDTSetNewURIs"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - *map(StringValue, new_uris) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + *map(StringValue, new_uris), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -845,17 +878,16 @@ def create_transaction_for_setting_new_uris(self, amount=None, gas_limit=self._config.gas_limit_set_new_uris, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_modifying_creator(self, - sender: Address, - token_identifier: str, - token_nonce: int) -> Transaction: + def create_transaction_for_modifying_creator( + self, sender: Address, token_identifier: str, token_nonce: int + ) -> Transaction: parts = [ "ESDTModifyCreator", self.serializer.serialize([StringValue(token_identifier)]), - self.serializer.serialize([BigUIntValue(token_nonce)]) + self.serializer.serialize([BigUIntValue(token_nonce)]), ] return TransactionBuilder( @@ -865,29 +897,33 @@ def create_transaction_for_modifying_creator(self, amount=None, gas_limit=self._config.gas_limit_esdt_modify_creator, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_updating_metadata(self, - sender: Address, - token_identifier: str, - token_nonce: int, - new_token_name: str, - new_royalties: int, - new_hash: str, - new_attributes: bytes, - new_uris: list[str]) -> Transaction: + def create_transaction_for_updating_metadata( + self, + sender: Address, + token_identifier: str, + token_nonce: int, + new_token_name: str, + new_royalties: int, + new_hash: str, + new_attributes: bytes, + new_uris: list[str], + ) -> Transaction: parts = ["ESDTMetaDataUpdate"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - StringValue(new_token_name), - BigUIntValue(new_royalties), - StringValue(new_hash), - BytesValue(new_attributes), - *map(StringValue, new_uris) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + StringValue(new_token_name), + BigUIntValue(new_royalties), + StringValue(new_hash), + BytesValue(new_attributes), + *map(StringValue, new_uris), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -898,29 +934,33 @@ def create_transaction_for_updating_metadata(self, amount=None, gas_limit=self._config.gas_limit_esdt_metadata_update, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_nft_metadata_recreate(self, - sender: Address, - token_identifier: str, - token_nonce: int, - new_token_name: str, - new_royalties: int, - new_hash: str, - new_attributes: bytes, - new_uris: list[str]) -> Transaction: + def create_transaction_for_nft_metadata_recreate( + self, + sender: Address, + token_identifier: str, + token_nonce: int, + new_token_name: str, + new_royalties: int, + new_hash: str, + new_attributes: bytes, + new_uris: list[str], + ) -> Transaction: parts = ["ESDTMetaDataRecreate"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - BigUIntValue(token_nonce), - StringValue(new_token_name), - BigUIntValue(new_royalties), - StringValue(new_hash), - BytesValue(new_attributes), - *map(StringValue, new_uris) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_identifier), + BigUIntValue(token_nonce), + StringValue(new_token_name), + BigUIntValue(new_royalties), + StringValue(new_hash), + BytesValue(new_attributes), + *map(StringValue, new_uris), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -931,16 +971,14 @@ def create_transaction_for_nft_metadata_recreate(self, amount=None, gas_limit=self._config.gas_limit_nft_metadata_recreate, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_changing_token_to_dynamic(self, - sender: Address, - token_identifier: str) -> Transaction: + def create_transaction_for_changing_token_to_dynamic(self, sender: Address, token_identifier: str) -> Transaction: """The following token types cannot be changed to dynamic: FungibleESDT, NonFungibleESDT, NonFungibleESDTv2""" parts = [ "changeToDynamic", - self.serializer.serialize([StringValue(token_identifier)]) + self.serializer.serialize([StringValue(token_identifier)]), ] return TransactionBuilder( @@ -950,15 +988,13 @@ def create_transaction_for_changing_token_to_dynamic(self, amount=None, gas_limit=self._config.gas_limit_nft_change_to_dynamic, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_updating_token_id(self, - sender: Address, - token_identifier: str) -> Transaction: + def create_transaction_for_updating_token_id(self, sender: Address, token_identifier: str) -> Transaction: parts = [ "updateTokenID", - self.serializer.serialize([StringValue(token_identifier)]) + self.serializer.serialize([StringValue(token_identifier)]), ] return TransactionBuilder( @@ -968,25 +1004,29 @@ def create_transaction_for_updating_token_id(self, amount=None, gas_limit=self._config.gas_limit_update_token_id, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_registering_dynamic_token(self, - sender: Address, - token_name: str, - token_ticker: str, - token_type: TokenType, - denominator: Optional[int] = None) -> Transaction: + def create_transaction_for_registering_dynamic_token( + self, + sender: Address, + token_name: str, + token_ticker: str, + token_type: TokenType, + denominator: Optional[int] = None, + ) -> Transaction: if token_type == TokenType.FNG: raise Exception("Cannot register fungible token as dynamic") parts = ["registerDynamic"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - StringValue(token_type.value) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + StringValue(token_type.value), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -1000,25 +1040,29 @@ def create_transaction_for_registering_dynamic_token(self, amount=self._config.issue_cost, gas_limit=self._config.gas_limit_register_dynamic, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_registering_dynamic_and_setting_roles(self, - sender: Address, - token_name: str, - token_ticker: str, - token_type: TokenType, - denominator: Optional[int] = None) -> Transaction: + def create_transaction_for_registering_dynamic_and_setting_roles( + self, + sender: Address, + token_name: str, + token_ticker: str, + token_type: TokenType, + denominator: Optional[int] = None, + ) -> Transaction: if token_type == TokenType.FNG: raise Exception("Cannot register fungible token as dynamic") parts = ["registerAndSetAllRolesDynamic"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_name), - StringValue(token_ticker), - StringValue(token_type.value) - ]) + serialized_parts = self.serializer.serialize_to_parts( + [ + StringValue(token_name), + StringValue(token_ticker), + StringValue(token_type.value), + ] + ) parts.extend([part.hex() for part in serialized_parts]) @@ -1032,17 +1076,16 @@ def create_transaction_for_registering_dynamic_and_setting_roles(self, amount=self._config.issue_cost, gas_limit=self._config.gas_limit_register_dynamic, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_transferring_ownership(self, - sender: Address, - token_identifier: str, - new_owner: Address) -> Transaction: + def create_transaction_for_transferring_ownership( + self, sender: Address, token_identifier: str, new_owner: Address + ) -> Transaction: parts = [ "transferOwnership", self.serializer.serialize([StringValue(token_identifier)]), - new_owner.to_hex() + new_owner.to_hex(), ] return TransactionBuilder( @@ -1052,19 +1095,17 @@ def create_transaction_for_transferring_ownership(self, amount=0, gas_limit=self._config.gas_limit_transfer_ownership, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_freezing_single_nft(self, - sender: Address, - token_identifier: str, - token_nonce: int, - user: Address) -> Transaction: + def create_transaction_for_freezing_single_nft( + self, sender: Address, token_identifier: str, token_nonce: int, user: Address + ) -> Transaction: parts = [ "freezeSingleNFT", self.serializer.serialize([StringValue(token_identifier)]), self.serializer.serialize([BigUIntValue(token_nonce)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -1074,19 +1115,17 @@ def create_transaction_for_freezing_single_nft(self, amount=0, gas_limit=self._config.gas_limit_freeze_single_nft, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_unfreezing_single_nft(self, - sender: Address, - token_identifier: str, - token_nonce: int, - user: Address) -> Transaction: + def create_transaction_for_unfreezing_single_nft( + self, sender: Address, token_identifier: str, token_nonce: int, user: Address + ) -> Transaction: parts = [ "unFreezeSingleNFT", self.serializer.serialize([StringValue(token_identifier)]), self.serializer.serialize([BigUIntValue(token_nonce)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -1096,17 +1135,16 @@ def create_transaction_for_unfreezing_single_nft(self, amount=0, gas_limit=self._config.gas_limit_unfreeze_single_nft, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_changing_sft_to_meta_esdt(self, - sender: Address, - collection: str, - num_decimals: int) -> Transaction: + def create_transaction_for_changing_sft_to_meta_esdt( + self, sender: Address, collection: str, num_decimals: int + ) -> Transaction: parts = [ "changeSFTToMetaESDT", self.serializer.serialize([StringValue(collection)]), - self.serializer.serialize([BigUIntValue(num_decimals)]) + self.serializer.serialize([BigUIntValue(num_decimals)]), ] return TransactionBuilder( @@ -1116,19 +1154,18 @@ def create_transaction_for_changing_sft_to_meta_esdt(self, amount=0, gas_limit=self._config.gas_limit_change_sft_to_meta_esdt, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_transferring_nft_create_role(self, - sender: Address, - token_identifier: str, - user: Address) -> Transaction: + def create_transaction_for_transferring_nft_create_role( + self, sender: Address, token_identifier: str, user: Address + ) -> Transaction: """This role can be transferred only if the `canTransferNFTCreateRole` property of the token is set to `true`.""" parts = [ "transferNFTCreateRole", self.serializer.serialize([StringValue(token_identifier)]), sender.to_hex(), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -1138,15 +1175,13 @@ def create_transaction_for_transferring_nft_create_role(self, amount=0, gas_limit=self._config.gas_limit_transfer_nft_create_role, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_stopping_nft_creation(self, - sender: Address, - token_identifier: str) -> Transaction: + def create_transaction_for_stopping_nft_creation(self, sender: Address, token_identifier: str) -> Transaction: parts = [ "stopNFTCreate", - self.serializer.serialize([StringValue(token_identifier)]) + self.serializer.serialize([StringValue(token_identifier)]), ] return TransactionBuilder( @@ -1156,19 +1191,17 @@ def create_transaction_for_stopping_nft_creation(self, amount=0, gas_limit=self._config.gas_limit_stop_nft_create, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transaction_for_wiping_single_nft(self, - sender: Address, - token_identifier: str, - token_nonce: int, - user: Address) -> Transaction: + def create_transaction_for_wiping_single_nft( + self, sender: Address, token_identifier: str, token_nonce: int, user: Address + ) -> Transaction: parts = [ "wipeSingleNFT", self.serializer.serialize([StringValue(token_identifier)]), self.serializer.serialize([BigUIntValue(token_nonce)]), - user.to_hex() + user.to_hex(), ] return TransactionBuilder( @@ -1178,19 +1211,13 @@ def create_transaction_for_wiping_single_nft(self, amount=0, gas_limit=self._config.gas_limit_wipe_single_nft, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() - def create_transction_for_adding_uris(self, - sender: Address, - token_identifier: str, - uris: list[str]) -> Transaction: + def create_transction_for_adding_uris(self, sender: Address, token_identifier: str, uris: list[str]) -> Transaction: parts = ["ESDTNFTAddURI"] - serialized_parts = self.serializer.serialize_to_parts([ - StringValue(token_identifier), - *map(StringValue, uris) - ]) + serialized_parts = self.serializer.serialize_to_parts([StringValue(token_identifier), *map(StringValue, uris)]) parts.extend([part.hex() for part in serialized_parts]) @@ -1201,7 +1228,7 @@ def create_transction_for_adding_uris(self, amount=0, gas_limit=self._config.gas_limit_esdt_nft_add_uri, add_data_movement_gas=True, - data_parts=parts + data_parts=parts, ).build() def _bool_to_typed_string(self, value: bool) -> StringValue: diff --git a/multiversx_sdk/token_management/token_management_transactions_factory_test.py b/multiversx_sdk/token_management/token_management_transactions_factory_test.py index ef574afb..bc3a0897 100644 --- a/multiversx_sdk/token_management/token_management_transactions_factory_test.py +++ b/multiversx_sdk/token_management/token_management_transactions_factory_test.py @@ -1,10 +1,11 @@ import pytest from multiversx_sdk.core import Address -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig from multiversx_sdk.token_management.token_management_transactions_factory import ( - TokenManagementTransactionsFactory, TokenType) + TokenManagementTransactionsFactory, + TokenType, +) frank = Address.new_from_bech32("erd1kdl46yctawygtwg2k462307dmz2v55c605737dp3zkxh04sct7asqylhyv") grace = Address.new_from_bech32("erd1r69gk66fmedhhcg24g2c5kn2f2a5k4kvpr6jfw67dn2lyydd8cfswy6ede") @@ -18,7 +19,7 @@ def test_create_transaction_for_registering_and_setting_roles(): token_name="TEST", token_ticker="TEST", token_type=TokenType.FNG, - num_decimals=2 + num_decimals=2, ) assert transaction.data @@ -40,11 +41,14 @@ def test_create_transaction_for_issuing_fungible(): can_pause=True, can_change_owner=True, can_upgrade=False, - can_add_special_roles=False + can_add_special_roles=False, ) assert transaction.data - assert transaction.data.decode() == "issue@4652414e4b@4652414e4b@64@@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + assert ( + transaction.data.decode() + == "issue@4652414e4b@4652414e4b@64@@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 50000000000000000 @@ -61,11 +65,14 @@ def test_create_transaction_for_issuing_semi_fungible(): can_transfer_nft_create_role=True, can_change_owner=True, can_upgrade=False, - can_add_special_roles=False + can_add_special_roles=False, ) assert transaction.data - assert transaction.data.decode() == "issueSemiFungible@4652414e4b@4652414e4b@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + assert ( + transaction.data.decode() + == "issueSemiFungible@4652414e4b@4652414e4b@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 50000000000000000 @@ -82,11 +89,14 @@ def test_create_transaction_for_issuing_non_fungible(): can_transfer_nft_create_role=True, can_change_owner=True, can_upgrade=False, - can_add_special_roles=False + can_add_special_roles=False, ) assert transaction.data - assert transaction.data.decode() == "issueNonFungible@4652414e4b@4652414e4b@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + assert ( + transaction.data.decode() + == "issueNonFungible@4652414e4b@4652414e4b@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 50000000000000000 @@ -104,11 +114,14 @@ def test_create_transaction_for_registering_meta_esdt(): can_transfer_nft_create_role=True, can_change_owner=True, can_upgrade=False, - can_add_special_roles=False + can_add_special_roles=False, ) assert transaction.data - assert transaction.data.decode() == "registerMetaESDT@4652414e4b@4652414e4b@0a@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + assert ( + transaction.data.decode() + == "registerMetaESDT@4652414e4b@4652414e4b@0a@63616e467265657a65@74727565@63616e57697065@74727565@63616e5061757365@74727565@63616e5472616e736665724e4654437265617465526f6c65@74727565@63616e4368616e67654f776e6572@74727565@63616e55706772616465@66616c7365@63616e4164645370656369616c526f6c6573@66616c7365" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 50000000000000000 @@ -125,11 +138,14 @@ def test_create_transaction_for_setting_special_role_on_non_fungible_token(): add_role_nft_add_uri=True, add_role_esdt_transfer_role=False, add_role_esdt_modify_creator=True, - add_role_nft_recreate=True + add_role_nft_recreate=True, ) assert transaction.data - assert transaction.data.decode() == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" + assert ( + transaction.data.decode() + == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -145,11 +161,14 @@ def test_create_transaction_for_unsetting_special_role_on_non_fungible_token(): remove_role_nft_remove_uri=True, remove_role_esdt_transfer_role=False, remove_role_esdt_modify_creator=True, - remove_role_nft_recreate=True + remove_role_nft_recreate=True, ) assert transaction.data - assert transaction.data.decode() == "unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" + assert ( + transaction.data.decode() + == "unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -160,11 +179,14 @@ def test_set_roles_on_nft(): sender=frank, user=grace, token_identifier="FRANK-11ce3e", - add_role_esdt_transfer_role=True + add_role_esdt_transfer_role=True, ) assert transaction.data - assert transaction.data.decode() == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@455344545472616e73666572526f6c65" + assert ( + transaction.data.decode() + == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@455344545472616e73666572526f6c65" + ) assert transaction.sender == frank assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -182,9 +204,12 @@ def test_set_roles_on_nft(): add_role_esdt_modify_creator=True, add_role_nft_recreate=True, add_role_esdt_transfer_role=True, - add_role_nft_add_uri=True + add_role_nft_add_uri=True, + ) + assert ( + transaction.data.decode() + == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@455344545472616e73666572526f6c65@45534454526f6c654e4654557064617465@45534454526f6c654d6f64696679526f79616c74696573@45534454526f6c655365744e6577555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" ) - assert transaction.data.decode() == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e465455706461746541747472696275746573@45534454526f6c654e4654416464555249@455344545472616e73666572526f6c65@45534454526f6c654e4654557064617465@45534454526f6c654d6f64696679526f79616c74696573@45534454526f6c655365744e6577555249@45534454526f6c654d6f6469667943726561746f72@45534454526f6c654e46545265637265617465" def test_create_transaction_for_creating_nft(): @@ -196,11 +221,13 @@ def test_create_transaction_for_creating_nft(): royalties=1000, hash="abba", attributes=bytes("test", "utf-8"), - uris=["a", "b"] + uris=["a", "b"], ) assert transaction.data - assert transaction.data.decode() == "ESDTNFTCreate@4652414e4b2d616139653864@01@74657374@03e8@61626261@74657374@61@62" + assert ( + transaction.data.decode() == "ESDTNFTCreate@4652414e4b2d616139653864@01@74657374@03e8@61626261@74657374@61@62" + ) assert transaction.sender.to_bech32() == grace.to_bech32() assert transaction.receiver.to_bech32() == grace.to_bech32() assert transaction.value == 0 @@ -215,12 +242,14 @@ def test_create_transaction_for_setting_special_role_on_fungible_token(): token_identifier="FRANK-11ce3e", add_role_local_mint=True, add_role_local_burn=False, - add_role_esdt_transfer_role=False + add_role_esdt_transfer_role=False, ) assert transaction.data - assert transaction.data.decode( - ) == f"setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}" + assert ( + transaction.data.decode() + == f"setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -234,12 +263,14 @@ def test_create_transaction_for_unsetting_special_role_on_fungible_token(): token_identifier="FRANK-11ce3e", remove_role_local_mint=True, remove_role_local_burn=False, - remove_role_esdt_transfer_role=False + remove_role_esdt_transfer_role=False, ) assert transaction.data - assert transaction.data.decode( - ) == f"unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}" + assert ( + transaction.data.decode() + == f"unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -255,11 +286,14 @@ def test_set_all_roles_on_fungible_token(): token_identifier="FRANK-11ce3e", add_role_local_mint=True, add_role_local_burn=True, - add_role_esdt_transfer_role=True + add_role_esdt_transfer_role=True, ) assert transaction.data - assert transaction.data.decode() == f"setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}@{burn_role_as_hex}@{transfer_role_as_hex}" + assert ( + transaction.data.decode() + == f"setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@{mint_role_as_hex}@{burn_role_as_hex}@{transfer_role_as_hex}" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -276,7 +310,10 @@ def test_create_transaction_for_setting_special_role_on_semi_fungible_token(): ) assert transaction.data - assert transaction.data.decode() == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e46544164645175616e74697479@455344545472616e73666572526f6c65" + assert ( + transaction.data.decode() + == "setSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e4654437265617465@45534454526f6c654e46544275726e@45534454526f6c654e46544164645175616e74697479@455344545472616e73666572526f6c65" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -292,7 +329,10 @@ def test_create_transaction_for_unsetting_special_role_on_semi_fungible_token(): ) assert transaction.data - assert transaction.data.decode() == "unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e46544275726e@45534454526f6c654e46544164645175616e74697479@455344545472616e73666572526f6c65" + assert ( + transaction.data.decode() + == "unSetSpecialRole@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13@45534454526f6c654e46544275726e@45534454526f6c654e46544164645175616e74697479@455344545472616e73666572526f6c65" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -329,7 +369,10 @@ def test_create_transaction_for_freezing(): ) assert transaction.data - assert transaction.data.decode() == "freeze@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + assert ( + transaction.data.decode() + == "freeze@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + ) assert transaction.sender == frank assert transaction.value == 0 @@ -342,16 +385,17 @@ def test_create_transaction_for_unfreezing(): ) assert transaction.data - assert transaction.data.decode() == "unFreeze@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + assert ( + transaction.data.decode() + == "unFreeze@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + ) assert transaction.sender == frank assert transaction.value == 0 def test_create_transaction_for_local_minting(): transaction = factory.create_transaction_for_local_minting( - sender=frank, - token_identifier="FRANK-11ce3e", - supply_to_mint=10 + sender=frank, token_identifier="FRANK-11ce3e", supply_to_mint=10 ) assert transaction.data @@ -362,9 +406,7 @@ def test_create_transaction_for_local_minting(): def test_create_transaction_for_local_burning(): transaction = factory.create_transaction_for_local_burning( - sender=frank, - token_identifier="FRANK-11ce3e", - supply_to_burn=10 + sender=frank, token_identifier="FRANK-11ce3e", supply_to_burn=10 ) assert transaction.data @@ -392,7 +434,7 @@ def test_create_transaction_for_adding_quantity(): sender=frank, token_identifier="FRANK-11ce3e", token_nonce=10, - quantity_to_add=10 + quantity_to_add=10, ) assert transaction.data @@ -406,7 +448,7 @@ def test_create_transaction_for_burning_quantity(): sender=frank, token_identifier="FRANK-11ce3e", token_nonce=10, - quantity_to_burn=10 + quantity_to_burn=10, ) assert transaction.data @@ -440,24 +482,20 @@ def test_create_transaction_for_unsetting_burn_role_globally(): def test_create_transaction_for_wiping(): - transaction = factory.create_transaction_for_wiping( - sender=frank, - user=grace, - token_identifier="FRANK-11ce3e" - ) + transaction = factory.create_transaction_for_wiping(sender=frank, user=grace, token_identifier="FRANK-11ce3e") assert transaction.data - assert transaction.data.decode() == "wipe@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + assert ( + transaction.data.decode() + == "wipe@4652414e4b2d313163653365@1e8a8b6b49de5b7be10aaa158a5a6a4abb4b56cc08f524bb5e6cd5f211ad3e13" + ) assert transaction.sender == frank assert transaction.value == 0 def test_create_transaction_for_modifying_royalties(): transaction = factory.create_transaction_for_modifying_royalties( - sender=alice, - token_identifier="TEST-123456", - token_nonce=1, - new_royalties=1234 + sender=alice, token_identifier="TEST-123456", token_nonce=1, new_royalties=1234 ) assert transaction.data.decode() == "ESDTModifyRoyalties@544553542d313233343536@01@04d2" @@ -472,7 +510,7 @@ def test_create_transaction_for_setting_new_uris(): sender=alice, token_identifier="TEST-123456", token_nonce=1, - new_uris=["firstURI", "secondURI"] + new_uris=["firstURI", "secondURI"], ) assert transaction.data.decode() == "ESDTSetNewURIs@544553542d313233343536@01@6669727374555249@7365636f6e64555249" @@ -505,11 +543,13 @@ def test_create_transaction_for_updating_metadata(): new_royalties=1234, new_hash="abba", new_attributes=b"test", - new_uris=["firstURI", "secondURI"] + new_uris=["firstURI", "secondURI"], ) - assert transaction.data.decode( - ) == "ESDTMetaDataUpdate@544553542d313233343536@01@54657374@04d2@61626261@74657374@6669727374555249@7365636f6e64555249" + assert ( + transaction.data.decode() + == "ESDTMetaDataUpdate@544553542d313233343536@01@54657374@04d2@61626261@74657374@6669727374555249@7365636f6e64555249" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == alice.to_bech32() assert transaction.value == 0 @@ -525,11 +565,13 @@ def test_create_transaction_for_recreating_metadata(): new_royalties=1234, new_hash="abba", new_attributes=b"test", - new_uris=["firstURI", "secondURI"] + new_uris=["firstURI", "secondURI"], ) - assert transaction.data.decode( - ) == "ESDTMetaDataRecreate@544553542d313233343536@01@54657374@04d2@61626261@74657374@6669727374555249@7365636f6e64555249" + assert ( + transaction.data.decode() + == "ESDTMetaDataRecreate@544553542d313233343536@01@54657374@04d2@61626261@74657374@6669727374555249@7365636f6e64555249" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == alice.to_bech32() assert transaction.value == 0 @@ -537,10 +579,7 @@ def test_create_transaction_for_recreating_metadata(): def test_create_transaction_for_changing_to_dynamic(): - transaction = factory.create_transaction_for_changing_token_to_dynamic( - sender=alice, - token_identifier="TEST-123456" - ) + transaction = factory.create_transaction_for_changing_token_to_dynamic(sender=alice, token_identifier="TEST-123456") assert transaction.data.decode() == "changeToDynamic@544553542d313233343536" assert transaction.sender == alice @@ -550,10 +589,7 @@ def test_create_transaction_for_changing_to_dynamic(): def test_create_transaction_for_updating_token_id(): - transaction = factory.create_transaction_for_updating_token_id( - sender=alice, - token_identifier="TEST-123456" - ) + transaction = factory.create_transaction_for_updating_token_id(sender=alice, token_identifier="TEST-123456") assert transaction.data.decode() == "updateTokenID@544553542d313233343536" assert transaction.sender == alice @@ -567,7 +603,7 @@ def test_create_transaction_for_registering_dynamic(): sender=alice, token_name="Test", token_ticker="TEST-123456", - token_type=TokenType.SFT + token_type=TokenType.SFT, ) assert transaction.data.decode() == "registerDynamic@54657374@544553542d313233343536@534654" @@ -582,7 +618,7 @@ def test_create_transaction_for_registering_and_setting_all_roles(): sender=alice, token_name="Test", token_ticker="TEST-123456", - token_type=TokenType.SFT + token_type=TokenType.SFT, ) assert transaction.data.decode() == "registerAndSetAllRolesDynamic@54657374@544553542d313233343536@534654" @@ -598,7 +634,7 @@ def test_register_invalid_dynamic(): sender=alice, token_name="Test", token_ticker="TEST-123456", - token_type=TokenType.FNG + token_type=TokenType.FNG, ) with pytest.raises(Exception, match="Cannot register fungible token as dynamic"): @@ -606,7 +642,7 @@ def test_register_invalid_dynamic(): sender=alice, token_name="Test", token_ticker="TEST-123456", - token_type=TokenType.FNG + token_type=TokenType.FNG, ) @@ -616,7 +652,7 @@ def test_register_dynamic_meta(): token_name="Test", token_ticker="TEST-987654", token_type=TokenType.META, - denominator=18 + denominator=18, ) assert transaction.data.decode() == "registerDynamic@54657374@544553542d393837363534@4d455441@12" @@ -632,7 +668,7 @@ def test_register_dynamic_and_set_all_roles_meta(): token_name="Test", token_ticker="TEST-987654", token_type=TokenType.META, - denominator=18 + denominator=18, ) assert transaction.data.decode() == "registerAndSetAllRolesDynamic@54657374@544553542d393837363534@4d455441@12" @@ -644,12 +680,13 @@ def test_register_dynamic_and_set_all_roles_meta(): def test_transfer_ownership(): transaction = factory.create_transaction_for_transferring_ownership( - sender=alice, - token_identifier="AND-1d56f2", - new_owner=frank + sender=alice, token_identifier="AND-1d56f2", new_owner=frank ) - assert transaction.data.decode() == "transferOwnership@414e442d316435366632@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + assert ( + transaction.data.decode() + == "transferOwnership@414e442d316435366632@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -658,13 +695,13 @@ def test_transfer_ownership(): def test_create_transaction_for_freezing_single_nft(): transaction = factory.create_transaction_for_freezing_single_nft( - sender=alice, - token_identifier="TEST-123456", - token_nonce=1, - user=frank + sender=alice, token_identifier="TEST-123456", token_nonce=1, user=frank ) - assert transaction.data.decode() == "freezeSingleNFT@544553542d313233343536@01@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + assert ( + transaction.data.decode() + == "freezeSingleNFT@544553542d313233343536@01@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -673,13 +710,13 @@ def test_create_transaction_for_freezing_single_nft(): def test_create_transaction_for_unfreezing_single_nft(): transaction = factory.create_transaction_for_unfreezing_single_nft( - sender=alice, - token_identifier="TEST-123456", - token_nonce=1, - user=frank + sender=alice, token_identifier="TEST-123456", token_nonce=1, user=frank ) - assert transaction.data.decode() == "unFreezeSingleNFT@544553542d313233343536@01@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + assert ( + transaction.data.decode() + == "unFreezeSingleNFT@544553542d313233343536@01@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -707,7 +744,10 @@ def test_create_transaction_for_transferring_nft_create_role(): user=frank, ) - assert transaction.data.decode() == "transferNFTCreateRole@5346542d313233343536@0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + assert ( + transaction.data.decode() + == "transferNFTCreateRole@5346542d313233343536@0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -715,10 +755,7 @@ def test_create_transaction_for_transferring_nft_create_role(): def test_create_transaction_for_stopping_nft_creation(): - transaction = factory.create_transaction_for_stopping_nft_creation( - sender=alice, - token_identifier="SFT-123456" - ) + transaction = factory.create_transaction_for_stopping_nft_creation(sender=alice, token_identifier="SFT-123456") assert transaction.data.decode() == "stopNFTCreate@5346542d313233343536" assert transaction.sender == alice @@ -735,7 +772,10 @@ def test_create_transaction_for_wiping_single_nft(): user=frank, ) - assert transaction.data.decode() == "wipeSingleNFT@5346542d313233343536@0a@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + assert ( + transaction.data.decode() + == "wipeSingleNFT@5346542d313233343536@0a@b37f5d130beb8885b90ab574a8bfcdd894ca531a7d3d1f3431158d77d6185fbb" + ) assert transaction.sender == alice assert transaction.receiver.to_bech32() == "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u" assert transaction.value == 0 @@ -744,9 +784,7 @@ def test_create_transaction_for_wiping_single_nft(): def test_create_transaction_for_adding_uris(): transaction = factory.create_transction_for_adding_uris( - sender=alice, - token_identifier="SFT-123456", - uris=["firstURI", "secondURI"] + sender=alice, token_identifier="SFT-123456", uris=["firstURI", "secondURI"] ) assert transaction.data.decode() == "ESDTNFTAddURI@5346542d313233343536@6669727374555249@7365636f6e64555249" diff --git a/multiversx_sdk/token_management/token_management_transactions_outcome_parser.py b/multiversx_sdk/token_management/token_management_transactions_outcome_parser.py index f3b3ed51..89a7b23b 100644 --- a/multiversx_sdk/token_management/token_management_transactions_outcome_parser.py +++ b/multiversx_sdk/token_management/token_management_transactions_outcome_parser.py @@ -3,13 +3,29 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.errors import ParseTransactionOnNetworkError from multiversx_sdk.core.transaction_on_network import ( - TransactionEvent, TransactionOnNetwork, find_events_by_identifier) + TransactionEvent, + TransactionOnNetwork, + find_events_by_identifier, +) from multiversx_sdk.token_management.token_management_transactions_outcome_parser_types import ( - AddQuantityOutcome, BurnOutcome, BurnQuantityOutcome, FreezeOutcome, - IssueFungibleOutcome, IssueNonFungibleOutcome, IssueSemiFungibleOutcome, - MintOutcome, NFTCreateOutcome, PauseOutcome, RegisterAndSetAllRolesOutcome, - RegisterMetaEsdtOutcome, SetSpecialRoleOutcome, UnFreezeOutcome, - UnPauseOutcome, UpdateAttributesOutcome, WipeOutcome) + AddQuantityOutcome, + BurnOutcome, + BurnQuantityOutcome, + FreezeOutcome, + IssueFungibleOutcome, + IssueNonFungibleOutcome, + IssueSemiFungibleOutcome, + MintOutcome, + NFTCreateOutcome, + PauseOutcome, + RegisterAndSetAllRolesOutcome, + RegisterMetaEsdtOutcome, + SetSpecialRoleOutcome, + UnFreezeOutcome, + UnPauseOutcome, + UpdateAttributesOutcome, + WipeOutcome, +) class TokenManagementTransactionsOutcomeParser: @@ -40,7 +56,9 @@ def parse_register_meta_esdt(self, transaction: TransactionOnNetwork) -> list[Re events = find_events_by_identifier(transaction, "registerMetaESDT") return [RegisterMetaEsdtOutcome(self._extract_token_identifier(event)) for event in events] - def parse_register_and_set_all_roles(self, transaction: TransactionOnNetwork) -> list[RegisterAndSetAllRolesOutcome]: + def parse_register_and_set_all_roles( + self, transaction: TransactionOnNetwork + ) -> list[RegisterAndSetAllRolesOutcome]: self._ensure_no_error(transaction.logs.events) register_events = find_events_by_identifier(transaction, "registerAndSetAllRoles") @@ -48,7 +66,8 @@ def parse_register_and_set_all_roles(self, transaction: TransactionOnNetwork) -> if len(register_events) != len(set_role_events): raise ParseTransactionOnNetworkError( - "The number of `registerAndSetAllRoles` events and `ESDTSetRole` events do not match") + "The number of `registerAndSetAllRoles` events and `ESDTSetRole` events do not match" + ) result: list[RegisterAndSetAllRolesOutcome] = [] for register_event, set_role_event in zip(register_events, set_role_events): @@ -72,7 +91,7 @@ def parse_set_special_role(self, transaction: TransactionOnNetwork) -> list[SetS SetSpecialRoleOutcome( user_address=event.address, token_identifier=self._extract_token_identifier(event), - roles=self._decode_roles(event) + roles=self._decode_roles(event), ) for event in events ] @@ -86,7 +105,7 @@ def parse_nft_create(self, transaction: TransactionOnNetwork) -> list[NFTCreateO NFTCreateOutcome( token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - initial_quantity=self._extract_amount(event) + initial_quantity=self._extract_amount(event), ) for event in events ] @@ -100,7 +119,7 @@ def parse_local_mint(self, transaction: TransactionOnNetwork) -> list[MintOutcom user_address=event.address, token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - minted_supply=self._extract_amount(event) + minted_supply=self._extract_amount(event), ) for event in events ] @@ -114,7 +133,7 @@ def parse_local_burn(self, transaction: TransactionOnNetwork) -> list[BurnOutcom user_address=event.address, token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - burnt_supply=self._extract_amount(event) + burnt_supply=self._extract_amount(event), ) for event in events ] @@ -140,7 +159,7 @@ def parse_freeze(self, transaction: TransactionOnNetwork) -> list[FreezeOutcome] user_address=self._extract_address(event), token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - balance=self._extract_amount(event) + balance=self._extract_amount(event), ) for event in events ] @@ -154,7 +173,7 @@ def parse_unfreeze(self, transaction: TransactionOnNetwork) -> list[UnFreezeOutc user_address=self._extract_address(event), token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - balance=self._extract_amount(event) + balance=self._extract_amount(event), ) for event in events ] @@ -168,7 +187,7 @@ def parse_wipe(self, transaction: TransactionOnNetwork) -> list[WipeOutcome]: user_address=self._extract_address(event), token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - balance=self._extract_amount(event) + balance=self._extract_amount(event), ) for event in events ] @@ -181,7 +200,7 @@ def parse_update_attributes(self, transaction: TransactionOnNetwork) -> list[Upd UpdateAttributesOutcome( token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - attributes=event.topics[3] if event.topics[3] else b"" + attributes=event.topics[3] if event.topics[3] else b"", ) for event in events ] @@ -194,7 +213,7 @@ def parse_add_quantity(self, transaction: TransactionOnNetwork) -> list[AddQuant AddQuantityOutcome( token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - added_quantity=self._extract_amount(event) + added_quantity=self._extract_amount(event), ) for event in events ] @@ -207,7 +226,7 @@ def parse_burn_quantity(self, transaction: TransactionOnNetwork) -> list[BurnQua BurnQuantityOutcome( token_identifier=self._extract_token_identifier(event), nonce=self._extract_nonce(event), - burnt_quantity=self._extract_amount(event) + burnt_quantity=self._extract_amount(event), ) for event in events ] @@ -218,7 +237,9 @@ def _ensure_no_error(self, transaction_events: list[TransactionEvent]) -> None: data = event.additional_data[0].decode()[1:] if len(event.additional_data[0]) else "" message = event.topics[1].decode() - raise ParseTransactionOnNetworkError(f"encountered signalError: {message} ({bytes.fromhex(data).decode()})") + raise ParseTransactionOnNetworkError( + f"encountered signalError: {message} ({bytes.fromhex(data).decode()})" + ) def _decode_roles(self, event: TransactionEvent) -> list[str]: encoded_roles = event.topics[3:] diff --git a/multiversx_sdk/token_management/token_management_transactions_outcome_parser_test.py b/multiversx_sdk/token_management/token_management_transactions_outcome_parser_test.py index f3dcb898..e957a44e 100644 --- a/multiversx_sdk/token_management/token_management_transactions_outcome_parser_test.py +++ b/multiversx_sdk/token_management/token_management_transactions_outcome_parser_test.py @@ -5,34 +5,44 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.errors import ParseTransactionOnNetworkError -from multiversx_sdk.core.transaction_on_network import (SmartContractResult, - TransactionEvent, - TransactionLogs) -from multiversx_sdk.testutils.mock_transaction_on_network import \ - get_empty_transaction_on_network +from multiversx_sdk.core.transaction_on_network import ( + SmartContractResult, + TransactionEvent, + TransactionLogs, +) +from multiversx_sdk.testutils.mock_transaction_on_network import ( + get_empty_transaction_on_network, +) from multiversx_sdk.testutils.utils import base64_topics_to_bytes -from multiversx_sdk.token_management.token_management_transactions_outcome_parser import \ - TokenManagementTransactionsOutcomeParser +from multiversx_sdk.token_management.token_management_transactions_outcome_parser import ( + TokenManagementTransactionsOutcomeParser, +) class TestTokenManagementTransactionsOutcomeParser: parser = TokenManagementTransactionsOutcomeParser() def test_ensure_error(self): - encoded_topics = ["Avk0jZ1kR+l9c76wQQoYcu4hvXPz+jxxTdqQeaCrbX8=", "dGlja2VyIG5hbWUgaXMgbm90IHZhbGlk"] + 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")] + additional_data=[base64.b64decode("QDc1NzM2NTcyMjA2NTcyNzI2Zjcy")], ) 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)")): + with pytest.raises( + ParseTransactionOnNetworkError, + match=re.escape("encountered signalError: ticker name is not valid (user error)"), + ): self.parser.parse_issue_fungible(tx) def test_parse_issue_fungible(self): @@ -43,7 +53,7 @@ def test_parse_issue_fungible(self): "U0VDT05E", "Wlpa", "RnVuZ2libGVFU0RU", - "Ag==" + "Ag==", ] event = TransactionEvent( raw={}, @@ -51,11 +61,13 @@ def test_parse_issue_fungible(self): identifier="issue", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_issue_fungible(tx) assert len(outcome) == 1 @@ -70,7 +82,7 @@ def test_parse_issue_non_fungible(self): "Y2FuVXBncmFkZQ==", "dHJ1ZQ==", "Y2FuQWRkU3BlY2lhbFJvbGVz", - "dHJ1ZQ==" + "dHJ1ZQ==", ] first_event = TransactionEvent( raw={}, @@ -78,40 +90,30 @@ def test_parse_issue_non_fungible(self): identifier="upgradeProperties", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) - encoded_topics = [ - "TkZULWYwMWQxZQ==", - "", - "", - "RVNEVFJvbGVCdXJuRm9yQWxs" - ] + encoded_topics = ["TkZULWYwMWQxZQ==", "", "", "RVNEVFJvbGVCdXJuRm9yQWxs"] second_event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTSetBurnRoleForAll", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) - encoded_topics = [ - identifier_base64, - "TkZURVNU", - "TkZU", - "Tm9uRnVuZ2libGVFU0RU" - ] + encoded_topics = [identifier_base64, "TkZURVNU", "TkZU", "Tm9uRnVuZ2libGVFU0RU"] third_event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="issueNonFungible", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() tx.logs = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), - [first_event, second_event, third_event] + [first_event, second_event, third_event], ) outcome = self.parser.parse_issue_non_fungible(tx) @@ -125,7 +127,7 @@ def test_parse_issue_semi_fungible(self): identifier_base64, "U0VNSQ==", "U0VNSUZORw==", - "U2VtaUZ1bmdpYmxlRVNEVA==" + "U2VtaUZ1bmdpYmxlRVNEVA==", ] event = TransactionEvent( raw={}, @@ -133,11 +135,13 @@ def test_parse_issue_semi_fungible(self): identifier="issueSemiFungible", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_issue_semi_fungible(tx) assert len(outcome) == 1 @@ -146,23 +150,20 @@ def test_parse_issue_semi_fungible(self): def test_parse_register_meta_esdt(self): identifier = "METATEST-e05d11" identifier_base64 = base64.b64encode(identifier.encode()).decode() - encoded_topics = [ - identifier_base64, - "TUVURVNU", - "TUVUQVRFU1Q=", - "TWV0YUVTRFQ=" - ] + encoded_topics = [identifier_base64, "TUVURVNU", "TUVUQVRFU1Q=", "TWV0YUVTRFQ="] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="registerMetaESDT", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_register_meta_esdt(tx) assert len(outcome) == 1 @@ -179,7 +180,7 @@ def test_parse_register_and_set_all_roles(self): "TE1BTw==", "TE1BTw==", "RnVuZ2libGVFU0RU", - "Ag==" + "Ag==", ] first_event = TransactionEvent( raw={}, @@ -187,27 +188,33 @@ def test_parse_register_and_set_all_roles(self): identifier="registerAndSetAllRoles", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) - encoded_topics = [second_identifier_base64, "TE1BTw==", "TE1BTw==", "RnVuZ2libGVFU0RU", "Ag=="] + 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), data=b"", - additional_data=[] + additional_data=[], ) tx_log = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), - [first_event, second_event] + [first_event, second_event], ) encoded_topics = [ "TE1BTy1kOWY4OTI=", "", "", "RVNEVFJvbGVMb2NhbE1pbnQ=", - "RVNEVFJvbGVMb2NhbEJ1cm4=" + "RVNEVFJvbGVMb2NhbEJ1cm4=", ] first_result_event = TransactionEvent( raw={}, @@ -215,14 +222,14 @@ def test_parse_register_and_set_all_roles(self): identifier="ESDTSetRole", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) encoded_topics = [ "VFNULTEyMzQ1Ng==", "", "", "RVNEVFJvbGVMb2NhbE1pbnQ=", - "RVNEVFJvbGVMb2NhbEJ1cm4=" + "RVNEVFJvbGVMb2NhbEJ1cm4=", ] second_result_event = TransactionEvent( raw={}, @@ -230,18 +237,18 @@ def test_parse_register_and_set_all_roles(self): identifier="ESDTSetRole", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) result_logs = TransactionLogs( Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), - [first_result_event, second_result_event] + [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 + logs=result_logs, ) tx = get_empty_transaction_on_network() @@ -265,7 +272,7 @@ def test_parse_set_special_role(self): "", "RVNEVFJvbGVORlRDcmVhdGU=", "RVNEVFJvbGVORlRBZGRRdWFudGl0eQ==", - "RVNEVFJvbGVORlRCdXJu" + "RVNEVFJvbGVORlRCdXJu", ] event = TransactionEvent( raw={}, @@ -273,11 +280,13 @@ def test_parse_set_special_role(self): identifier="ESDTSetRole", topics=base64_topics_to_bytes(encoded_roles), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_set_special_role(tx) assert len(outcome) == 1 @@ -294,7 +303,7 @@ def test_parse_nft_create(self): identifier_base64, "AQ==", "AQ==", - "CAESAgABIuUBCAESCE5GVEZJUlNUGiA8NdfqyxqZpKDMqlN+8MwK4Qn0H2wrQCID5jO/uwcfXCDEEyouUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4RzJDaHR0cHM6Ly9pcGZzLmlvL2lwZnMvUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4Rzo9dGFnczo7bWV0YWRhdGE6UW1SY1A5NGtYcjV6WmpSR3ZpN21KNnVuN0xweFVoWVZSNFI0UnBpY3h6Z1lrdA==" + "CAESAgABIuUBCAESCE5GVEZJUlNUGiA8NdfqyxqZpKDMqlN+8MwK4Qn0H2wrQCID5jO/uwcfXCDEEyouUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4RzJDaHR0cHM6Ly9pcGZzLmlvL2lwZnMvUW1ZM3ZKQ3NVcWpNM3hxeGR3VWczemJoVFNMUWZoN0szbW5aWXhyaGNRRFl4Rzo9dGFnczo7bWV0YWRhdGE6UW1SY1A5NGtYcjV6WmpSR3ZpN21KNnVuN0xweFVoWVZSNFI0UnBpY3h6Z1lrdA==", ] event = TransactionEvent( raw={}, @@ -302,11 +311,13 @@ def test_parse_nft_create(self): identifier="ESDTNFTCreate", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_nft_create(tx) assert len(outcome) == 1 @@ -319,22 +330,20 @@ def test_parse_local_mint(self): identifier_base64 = base64.b64encode(identifier.encode()).decode() nonce = 0 minted_supply = 100000 - encoded_topics = [ - identifier_base64, - "", - "AYag" - ] + encoded_topics = [identifier_base64, "", "AYag"] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTLocalMint", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_local_mint(tx) assert len(outcome) == 1 @@ -348,22 +357,20 @@ def test_parse_local_burn(self): identifier_base64 = base64.b64encode(identifier.encode()).decode() nonce = 0 burnt_supply = 100000 - encoded_topics = [ - identifier_base64, - "", - "AYag" - ] + encoded_topics = [identifier_base64, "", "AYag"] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTLocalBurn", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_local_burn(tx) assert len(outcome) == 1 @@ -381,11 +388,13 @@ def test_parse_pause(self): identifier="ESDTPause", topics=base64_topics_to_bytes([identifier_base64]), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_pause(tx) assert len(outcome) == 1 @@ -400,11 +409,13 @@ def test_parse_unpause(self): identifier="ESDTUnPause", topics=base64_topics_to_bytes([identifier_base64]), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), + [event], + ) outcome = self.parser.parse_unpause(tx) assert len(outcome) == 1 @@ -420,7 +431,7 @@ def test_parse_freeze(self): identifier_base64, "", "mJaA", - "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", ] event = TransactionEvent( raw={}, @@ -428,16 +439,18 @@ def test_parse_freeze(self): identifier="ESDTFreeze", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], + ) + tx_log = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], ) - 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 + logs=tx_log, ) tx = get_empty_transaction_on_network() tx.smart_contract_results = [sc_result] @@ -459,7 +472,7 @@ def test_parse_unfreeze(self): identifier_base64, "", "mJaA", - "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", ] event = TransactionEvent( raw={}, @@ -467,16 +480,18 @@ def test_parse_unfreeze(self): identifier="ESDTUnFreeze", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], + ) + tx_log = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], ) - 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 + logs=tx_log, ) tx = get_empty_transaction_on_network() tx.smart_contract_results = [sc_result] @@ -498,7 +513,7 @@ def test_parse_wipe(self): identifier_base64, "", "mJaA", - "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=" + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", ] event = TransactionEvent( raw={}, @@ -506,16 +521,18 @@ def test_parse_wipe(self): identifier="ESDTWipe", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], + ) + tx_log = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], ) - 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 + logs=tx_log, ) tx = get_empty_transaction_on_network() tx.smart_contract_results = [sc_result] @@ -533,23 +550,20 @@ def test_parse_update_attributes(self): nonce = 1 attributes = "metadata:ipfsCID/test.json;tags:tag1,tag2" attributes_base64 = base64.b64encode(attributes.encode()).decode() - encoded_topics = [ - identifier_base64, - "AQ==", - "", - attributes_base64 - ] + encoded_topics = [identifier_base64, "AQ==", "", attributes_base64] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTUpdateAttributes", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], + ) outcome = self.parser.parse_update_attributes(tx) assert len(outcome) == 1 @@ -562,22 +576,20 @@ def test_parse_add_quantity(self): identifier_base64 = base64.b64encode(identifier.encode()).decode() nonce = 1 added_quantity = 10 - encoded_topics = [ - identifier_base64, - "AQ==", - "Cg==" - ] + encoded_topics = [identifier_base64, "AQ==", "Cg=="] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTAddQuantity", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], + ) outcome = self.parser.parse_add_quantity(tx) assert len(outcome) == 1 @@ -590,22 +602,20 @@ def test_parse_burn_quantity(self): identifier_base64 = base64.b64encode(identifier.encode()).decode() nonce = 1 burnt_quantity = 16 - encoded_topics = [ - identifier_base64, - "AQ==", - "EA==" - ] + encoded_topics = [identifier_base64, "AQ==", "EA=="] event = TransactionEvent( raw={}, address=Address.new_from_bech32("erd18s6a06ktr2v6fgxv4ffhauxvptssnaqlds45qgsrucemlwc8rawq553rt2"), identifier="ESDTNFTBurn", topics=base64_topics_to_bytes(encoded_topics), data=b"", - additional_data=[] + additional_data=[], ) tx = get_empty_transaction_on_network() - tx.logs = TransactionLogs(Address.new_from_bech32( - "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), [event]) + tx.logs = TransactionLogs( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + [event], + ) outcome = self.parser.parse_burn_quantity(tx) assert len(outcome) == 1 diff --git a/multiversx_sdk/transfers/__init__.py b/multiversx_sdk/transfers/__init__.py index b33651a6..d31fe5c0 100644 --- a/multiversx_sdk/transfers/__init__.py +++ b/multiversx_sdk/transfers/__init__.py @@ -1,5 +1,6 @@ -from multiversx_sdk.transfers.transfer_transactions_factory import \ - TransferTransactionsFactory +from multiversx_sdk.transfers.transfer_transactions_factory import ( + TransferTransactionsFactory, +) from multiversx_sdk.transfers.transfers_controller import TransfersController __all__ = ["TransferTransactionsFactory", "TransfersController"] diff --git a/multiversx_sdk/transfers/transfer_transactions_factory.py b/multiversx_sdk/transfers/transfer_transactions_factory.py index d128118f..ebb7117a 100644 --- a/multiversx_sdk/transfers/transfer_transactions_factory.py +++ b/multiversx_sdk/transfers/transfer_transactions_factory.py @@ -1,15 +1,13 @@ from typing import Optional -from multiversx_sdk.builders.token_transfers_data_builder import \ - TokenTransfersDataBuilder +from multiversx_sdk.builders.token_transfers_data_builder import ( + TokenTransfersDataBuilder, +) from multiversx_sdk.builders.transaction_builder import TransactionBuilder -from multiversx_sdk.core import (Address, TokenComputer, TokenTransfer, - Transaction) -from multiversx_sdk.core.constants import \ - EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER +from multiversx_sdk.core import Address, TokenComputer, TokenTransfer, Transaction +from multiversx_sdk.core.constants import EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER from multiversx_sdk.core.errors import BadUsageError -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig ADDITIONAL_GAS_FOR_ESDT_TRANSFER = 100000 ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER = 800000 @@ -21,11 +19,13 @@ def __init__(self, config: TransactionsFactoryConfig) -> None: self.token_computer = TokenComputer() self._data_args_builder = TokenTransfersDataBuilder(self.token_computer) - def create_transaction_for_native_token_transfer(self, - sender: Address, - receiver: Address, - native_amount: int, - data: Optional[str] = None) -> Transaction: + def create_transaction_for_native_token_transfer( + self, + sender: Address, + receiver: Address, + native_amount: int, + data: Optional[str] = None, + ) -> Transaction: transaction_data = data if data else "" return TransactionBuilder( config=self.config, @@ -34,13 +34,12 @@ def create_transaction_for_native_token_transfer(self, data_parts=[transaction_data], gas_limit=0, add_data_movement_gas=True, - amount=native_amount + amount=native_amount, ).build() - def create_transaction_for_esdt_token_transfer(self, - sender: Address, - receiver: Address, - token_transfers: list[TokenTransfer]) -> Transaction: + def create_transaction_for_esdt_token_transfer( + self, sender: Address, receiver: Address, token_transfers: list[TokenTransfer] + ) -> Transaction: if not token_transfers: raise BadUsageError("No token transfer has been provided") @@ -55,13 +54,12 @@ def create_transaction_for_esdt_token_transfer(self, receiver=receiver, data_parts=data_parts, gas_limit=extra_gas_for_transfer, - add_data_movement_gas=True + add_data_movement_gas=True, ).build() - def _single_transfer(self, - sender: Address, - receiver: Address, - transfer: TokenTransfer) -> tuple[list[str], int, Address]: + def _single_transfer( + self, sender: Address, receiver: Address, transfer: TokenTransfer + ) -> tuple[list[str], int, Address]: if self.token_computer.is_fungible(transfer.token): if transfer.token.identifier == EGLD_IDENTIFIER_FOR_MULTI_ESDTNFT_TRANSFER: data_parts = self._data_args_builder.build_args_for_multi_esdt_nft_transfer(receiver, [transfer]) @@ -76,21 +74,23 @@ def _single_transfer(self, gas = self.config.gas_limit_esdt_nft_transfer + ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER return data_parts, gas, sender - def _multi_transfer(self, - sender: Address, - receiver: Address, - token_transfers: list[TokenTransfer]) -> tuple[list[str], int, Address]: + def _multi_transfer( + self, sender: Address, receiver: Address, token_transfers: list[TokenTransfer] + ) -> tuple[list[str], int, Address]: data_parts = self._data_args_builder.build_args_for_multi_esdt_nft_transfer(receiver, token_transfers) - gas = self.config.gas_limit_multi_esdt_nft_transfer * len( - token_transfers) + ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER + gas = ( + self.config.gas_limit_multi_esdt_nft_transfer * len(token_transfers) + ADDITIONAL_GAS_FOR_ESDT_NFT_TRANSFER + ) return data_parts, gas, sender - def create_transaction_for_transfer(self, - sender: Address, - receiver: Address, - native_amount: Optional[int] = None, - token_transfers: Optional[list[TokenTransfer]] = None, - data: Optional[bytes] = None) -> Transaction: + def create_transaction_for_transfer( + self, + sender: Address, + receiver: Address, + native_amount: Optional[int] = None, + token_transfers: Optional[list[TokenTransfer]] = None, + data: Optional[bytes] = None, + ) -> Transaction: if token_transfers and data: raise BadUsageError("Can't set data field when sending esdt tokens") @@ -100,7 +100,7 @@ def create_transaction_for_transfer(self, sender=sender, receiver=receiver, native_amount=native_amount, - data=data.decode() if data else None + data=data.decode() if data else None, ) token_transfers = list(token_transfers) if token_transfers else [] @@ -109,7 +109,5 @@ def create_transaction_for_transfer(self, token_transfers.append(native_transfer) if native_transfer else None return self.create_transaction_for_esdt_token_transfer( - sender=sender, - receiver=receiver, - token_transfers=token_transfers + sender=sender, receiver=receiver, token_transfers=token_transfers ) diff --git a/multiversx_sdk/transfers/transfer_transactions_factory_test.py b/multiversx_sdk/transfers/transfer_transactions_factory_test.py index d6508858..580bb333 100644 --- a/multiversx_sdk/transfers/transfer_transactions_factory_test.py +++ b/multiversx_sdk/transfers/transfer_transactions_factory_test.py @@ -2,10 +2,10 @@ from multiversx_sdk.core import Address, Token, TokenTransfer from multiversx_sdk.core.errors import BadUsageError -from multiversx_sdk.core.transactions_factory_config import \ - TransactionsFactoryConfig -from multiversx_sdk.transfers.transfer_transactions_factory import \ - TransferTransactionsFactory +from multiversx_sdk.core.transactions_factory_config import TransactionsFactoryConfig +from multiversx_sdk.transfers.transfer_transactions_factory import ( + TransferTransactionsFactory, +) class TestTransferTransactionsFactory: @@ -15,9 +15,7 @@ class TestTransferTransactionsFactory: def test_create_transaction_for_native_token_transfer_no_data(self): transaction = self.transfer_factory.create_transaction_for_native_token_transfer( - sender=self.alice, - receiver=self.bob, - native_amount=1000000000000000000 + sender=self.alice, receiver=self.bob, native_amount=1000000000000000000 ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -32,7 +30,7 @@ def test_create_transaction_for_native_token_transfer_with_data(self): sender=self.alice, receiver=self.bob, native_amount=1000000000000000000, - data="test data" + data="test data", ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -47,9 +45,7 @@ def test_create_transaction_for_esdt_transfer(self): token_transfer = TokenTransfer(foo_token, 1000000) transaction = self.transfer_factory.create_transaction_for_esdt_token_transfer( - sender=self.alice, - receiver=self.bob, - token_transfers=[token_transfer] + sender=self.alice, receiver=self.bob, token_transfers=[token_transfer] ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -64,16 +60,17 @@ def test_create_transaction_for_nft_transfer(self): token_transfer = TokenTransfer(nft, 1) transaction = self.transfer_factory.create_transaction_for_esdt_token_transfer( - sender=self.alice, - receiver=self.bob, - token_transfers=[token_transfer] + sender=self.alice, receiver=self.bob, token_transfers=[token_transfer] ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "ESDTNFTTransfer@4e46542d313233343536@0a@01@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + assert ( + transaction.data.decode() + == "ESDTNFTTransfer@4e46542d313233343536@0a@01@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + ) assert transaction.gas_limit == 1_210_500 def test_create_transaction_for_multiple_nft_transfers(self): @@ -86,20 +83,23 @@ def test_create_transaction_for_multiple_nft_transfers(self): transaction = self.transfer_factory.create_transaction_for_esdt_token_transfer( sender=self.alice, receiver=self.bob, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@02@4e46542d313233343536@0a@01@544553542d393837363534@01@01" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@02@4e46542d313233343536@0a@01@544553542d393837363534@01@01" + ) assert transaction.gas_limit == 1_466_000 second_transaction = self.transfer_factory.create_transaction_for_transfer( sender=self.alice, receiver=self.bob, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert second_transaction == transaction @@ -112,7 +112,7 @@ def test_create_transaction_for_token_transfer_with_errors(self): sender=self.alice, receiver=self.bob, token_transfers=[transfer], - data="hello".encode() + data="hello".encode(), ) def test_create_transaction_for_native_transfer(self): @@ -133,7 +133,7 @@ def test_create_transaction_for_native_transfer_and_set_data_field(self): sender=self.alice, receiver=self.bob, native_amount=1000000000000000000, - data="hello".encode() + data="hello".encode(), ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -144,9 +144,7 @@ def test_create_transaction_for_native_transfer_and_set_data_field(self): def test_create_transaction_for_notarizing(self): transaction = self.transfer_factory.create_transaction_for_transfer( - sender=self.alice, - receiver=self.bob, - data="hello".encode() + sender=self.alice, receiver=self.bob, data="hello".encode() ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" @@ -166,14 +164,17 @@ def test_create_transaction_for_token_transfer(self): sender=self.alice, receiver=self.bob, native_amount=1000000000000000000, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@4e46542d313233343536@0a@01@544553542d393837363534@01@01@45474c442d303030303030@@0de0b6b3a7640000" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@4e46542d313233343536@0a@01@544553542d393837363534@01@01@45474c442d303030303030@@0de0b6b3a7640000" + ) assert transaction.gas_limit == 1_727_500 def test_egld_as_single_token_transfer(self): @@ -181,16 +182,17 @@ def test_egld_as_single_token_transfer(self): transfer = TokenTransfer(egld, 1000000000000000000) transaction = self.transfer_factory.create_transaction_for_transfer( - sender=self.alice, - receiver=self.bob, - token_transfers=[transfer] + sender=self.alice, receiver=self.bob, token_transfers=[transfer] ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@01@45474c442d303030303030@@0de0b6b3a7640000" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@01@45474c442d303030303030@@0de0b6b3a7640000" + ) assert transaction.gas_limit == 1_243_500 def test_create_nft_transfer_with_prefix(self): @@ -198,17 +200,17 @@ def test_create_nft_transfer_with_prefix(self): transfer = TokenTransfer(nft, 1) transaction = self.transfer_factory.create_transaction_for_esdt_token_transfer( - sender=self.alice, - receiver=self.bob, - token_transfers=[transfer] + sender=self.alice, receiver=self.bob, token_transfers=[transfer] ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode( - ) == "ESDTNFTTransfer@74302d4e46542d313233343536@0a@01@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + assert ( + transaction.data.decode() + == "ESDTNFTTransfer@74302d4e46542d313233343536@0a@01@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + ) assert transaction.gas_limit == 1_219_500 def test_multiple_nft_transfers_with_prefix(self): @@ -221,20 +223,23 @@ def test_multiple_nft_transfers_with_prefix(self): transaction = self.transfer_factory.create_transaction_for_esdt_token_transfer( sender=self.alice, receiver=self.bob, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@02@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@01@01" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@02@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@01@01" + ) assert transaction.gas_limit == 1_484_000 second_transaction = self.transfer_factory.create_transaction_for_transfer( sender=self.alice, receiver=self.bob, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert second_transaction == transaction @@ -249,12 +254,15 @@ def test_multiple_token_transfers_with_prefix(self): sender=self.alice, receiver=self.bob, native_amount=1000000000000000000, - token_transfers=[first_transfer, second_transfer] + token_transfers=[first_transfer, second_transfer], ) assert transaction.sender.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.receiver.to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" assert transaction.value == 0 assert transaction.chain_id == "D" - assert transaction.data.decode() == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@@01@45474c442d303030303030@@0de0b6b3a7640000" + assert ( + transaction.data.decode() + == "MultiESDTNFTTransfer@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8@03@74302d4e46542d313233343536@0a@01@74302d544553542d393837363534@@01@45474c442d303030303030@@0de0b6b3a7640000" + ) assert transaction.gas_limit == 1_742_500 diff --git a/multiversx_sdk/wallet/__init__.py b/multiversx_sdk/wallet/__init__.py index dd83d268..65a0f6e8 100644 --- a/multiversx_sdk/wallet/__init__.py +++ b/multiversx_sdk/wallet/__init__.py @@ -5,16 +5,23 @@ from multiversx_sdk.wallet.user_signer import UserSigner from multiversx_sdk.wallet.user_verifer import UserVerifier from multiversx_sdk.wallet.user_wallet import UserWallet -from multiversx_sdk.wallet.validator_keys import (ValidatorPublicKey, - ValidatorSecretKey) +from multiversx_sdk.wallet.validator_keys import ValidatorPublicKey, ValidatorSecretKey from multiversx_sdk.wallet.validator_pem import ValidatorPEM from multiversx_sdk.wallet.validator_signer import ValidatorSigner from multiversx_sdk.wallet.validator_verifier import ValidatorVerifier __all__ = [ - "UserSigner", "Mnemonic", "UserSecretKey", - "UserPublicKey", "ValidatorSecretKey", - "ValidatorPublicKey", "UserVerifier", - "ValidatorSigner", "ValidatorVerifier", "ValidatorPEM", - "UserWallet", "UserPEM", "KeyPair" + "UserSigner", + "Mnemonic", + "UserSecretKey", + "UserPublicKey", + "ValidatorSecretKey", + "ValidatorPublicKey", + "UserVerifier", + "ValidatorSigner", + "ValidatorVerifier", + "ValidatorPEM", + "UserWallet", + "UserPEM", + "KeyPair", ] diff --git a/multiversx_sdk/wallet/core.py b/multiversx_sdk/wallet/core.py index dff1876e..4b930d09 100644 --- a/multiversx_sdk/wallet/core.py +++ b/multiversx_sdk/wallet/core.py @@ -6,7 +6,7 @@ BIP39_SALT_MODIFIER = "mnemonic" BIP39_PBKDF2_ROUNDS = 2048 -BIP32_SEED_MODIFIER = b'ed25519 seed' +BIP32_SEED_MODIFIER = b"ed25519 seed" BIP39_DERIVATION_PATH = [44, 508, 0, 0] HARDENED_OFFSET = 0x80000000 @@ -49,7 +49,7 @@ def bip39seed_to_secret_key(seed: bytes, address_index: int = 0): # Reference: https://github.com/alepop/ed25519-hd-key def _ckd_priv(key: bytes, chain_code: bytes, index: int): - index_buffer = struct.pack('>I', index) + index_buffer = struct.pack(">I", index) data = bytearray([0]) + bytearray(key) + bytearray(index_buffer) hashed = hmac.new(chain_code, data, hashlib.sha512).digest() key, chain_code = hashed[:32], hashed[32:] diff --git a/multiversx_sdk/wallet/crypto/__init__.py b/multiversx_sdk/wallet/crypto/__init__.py index 19b035ac..ee3fd46b 100644 --- a/multiversx_sdk/wallet/crypto/__init__.py +++ b/multiversx_sdk/wallet/crypto/__init__.py @@ -3,8 +3,8 @@ from multiversx_sdk.wallet.crypto.randomness import Randomness __all__ = [ - 'EncryptedData', - 'Randomness', - 'encryptor', - 'decryptor', + "EncryptedData", + "Randomness", + "encryptor", + "decryptor", ] diff --git a/multiversx_sdk/wallet/crypto/constants.py b/multiversx_sdk/wallet/crypto/constants.py index 858fe1f7..9d4954c9 100644 --- a/multiversx_sdk/wallet/crypto/constants.py +++ b/multiversx_sdk/wallet/crypto/constants.py @@ -1,5 +1,5 @@ -CIPHER_ALGORITHM_AES_128_CTR = 'aes-128-ctr' -KEY_DERIVATION_FUNCTION_SCRYPT = 'scrypt' +CIPHER_ALGORITHM_AES_128_CTR = "aes-128-ctr" +KEY_DERIVATION_FUNCTION_SCRYPT = "scrypt" RANDOM_SALT_LENGTH = 32 RANDOM_IV_LENGTH = 16 ENCRYPTOR_VERSION = 4 diff --git a/multiversx_sdk/wallet/crypto/decryptor.py b/multiversx_sdk/wallet/crypto/decryptor.py index 62f28d7f..d5fdc16c 100644 --- a/multiversx_sdk/wallet/crypto/decryptor.py +++ b/multiversx_sdk/wallet/crypto/decryptor.py @@ -4,11 +4,15 @@ from cryptography.hazmat.primitives.kdf.scrypt import Scrypt from multiversx_sdk.wallet.crypto.constants import ( - CIPHER_ALGORITHM_AES_128_CTR, KEY_DERIVATION_FUNCTION_SCRYPT) + CIPHER_ALGORITHM_AES_128_CTR, + KEY_DERIVATION_FUNCTION_SCRYPT, +) from multiversx_sdk.wallet.crypto.encrypted_data import EncryptedData -from multiversx_sdk.wallet.errors import (InvalidKeystoreFilePasswordError, - UnknownCipherError, - UnknownDerivationFunctionError) +from multiversx_sdk.wallet.errors import ( + InvalidKeystoreFilePasswordError, + UnknownCipherError, + UnknownDerivationFunctionError, +) def decrypt(encrypted_data: EncryptedData, password: str) -> bytes: @@ -33,7 +37,7 @@ def decrypt(encrypted_data: EncryptedData, password: str) -> bytes: n=encrypted_data.kdfparams.n, r=encrypted_data.kdfparams.r, p=encrypted_data.kdfparams.p, - backend=backend + backend=backend, ) derived_key = kdf.derive(bytes(password.encode())) diff --git a/multiversx_sdk/wallet/crypto/encrypted_data.py b/multiversx_sdk/wallet/crypto/encrypted_data.py index 7de80312..a701c70b 100644 --- a/multiversx_sdk/wallet/crypto/encrypted_data.py +++ b/multiversx_sdk/wallet/crypto/encrypted_data.py @@ -2,11 +2,7 @@ class KeyDerivationParams: - def __init__(self, - n: int, - r: int, - p: int, - dklen: int): + def __init__(self, n: int, r: int, p: int, dklen: int): # numIterations self.n = n # memFactor @@ -17,16 +13,18 @@ def __init__(self, class EncryptedData: - def __init__(self, - id: str, - version: int, - cipher: str, - ciphertext: str, - iv: str, - kdf: str, - kdfparams: KeyDerivationParams, - salt: str, - mac: str): + def __init__( + self, + id: str, + version: int, + cipher: str, + ciphertext: str, + iv: str, + kdf: str, + kdfparams: KeyDerivationParams, + salt: str, + mac: str, + ): self.id = id self.version = version self.cipher = cipher diff --git a/multiversx_sdk/wallet/crypto/encryptor.py b/multiversx_sdk/wallet/crypto/encryptor.py index cb1ad585..b277d872 100644 --- a/multiversx_sdk/wallet/crypto/encryptor.py +++ b/multiversx_sdk/wallet/crypto/encryptor.py @@ -4,10 +4,14 @@ from cryptography.hazmat.primitives.kdf.scrypt import Scrypt from multiversx_sdk.wallet.crypto.constants import ( - CIPHER_ALGORITHM_AES_128_CTR, ENCRYPTOR_VERSION, - KEY_DERIVATION_FUNCTION_SCRYPT) -from multiversx_sdk.wallet.crypto.encrypted_data import (EncryptedData, - KeyDerivationParams) + CIPHER_ALGORITHM_AES_128_CTR, + ENCRYPTOR_VERSION, + KEY_DERIVATION_FUNCTION_SCRYPT, +) +from multiversx_sdk.wallet.crypto.encrypted_data import ( + EncryptedData, + KeyDerivationParams, +) from multiversx_sdk.wallet.interfaces import IRandomness @@ -18,11 +22,22 @@ def encrypt(data: bytes, password: str, randomness: IRandomness) -> EncryptedDat backend = default_backend() kdParams = KeyDerivationParams(n=4096, r=8, p=1, dklen=32) - kdf = Scrypt(salt=randomness.salt, length=kdParams.dklen, n=kdParams.n, r=kdParams.r, p=kdParams.p, backend=backend) + kdf = Scrypt( + salt=randomness.salt, + length=kdParams.dklen, + n=kdParams.n, + r=kdParams.r, + p=kdParams.p, + backend=backend, + ) derived_key = kdf.derive(bytes(password.encode())) derived_key_first_half = derived_key[0:16] derived_key_second_half = derived_key[16:32] - cipher = Cipher(algorithms.AES(derived_key_first_half), modes.CTR(randomness.iv), backend=backend) + cipher = Cipher( + algorithms.AES(derived_key_first_half), + modes.CTR(randomness.iv), + backend=backend, + ) encryptor = cipher.encryptor() ciphertext = encryptor.update(data) + encryptor.finalize() @@ -40,7 +55,7 @@ def encrypt(data: bytes, password: str, randomness: IRandomness) -> EncryptedDat kdf=KEY_DERIVATION_FUNCTION_SCRYPT, kdfparams=kdParams, salt=randomness.salt.hex(), - mac=mac.hex() + mac=mac.hex(), ) return encrypted_data diff --git a/multiversx_sdk/wallet/crypto/randomness.py b/multiversx_sdk/wallet/crypto/randomness.py index 72a521bf..f9d1c11e 100644 --- a/multiversx_sdk/wallet/crypto/randomness.py +++ b/multiversx_sdk/wallet/crypto/randomness.py @@ -2,12 +2,16 @@ from typing import Optional from uuid import uuid4 -from multiversx_sdk.wallet.crypto.constants import (RANDOM_IV_LENGTH, - RANDOM_SALT_LENGTH) +from multiversx_sdk.wallet.crypto.constants import RANDOM_IV_LENGTH, RANDOM_SALT_LENGTH class Randomness: - def __init__(self, salt: Optional[bytes] = None, iv: Optional[bytes] = None, id: Optional[str] = None): + def __init__( + self, + salt: Optional[bytes] = None, + iv: Optional[bytes] = None, + id: Optional[str] = None, + ): self.salt = salt or os.urandom(RANDOM_SALT_LENGTH) self.iv = iv or os.urandom(RANDOM_IV_LENGTH) self.id = id or str(uuid4()) diff --git a/multiversx_sdk/wallet/keypair_test.py b/multiversx_sdk/wallet/keypair_test.py index 15bee653..1dfa6396 100644 --- a/multiversx_sdk/wallet/keypair_test.py +++ b/multiversx_sdk/wallet/keypair_test.py @@ -1,10 +1,9 @@ from multiversx_sdk.core.address import Address from multiversx_sdk.core.transaction import Transaction +from multiversx_sdk.core.transaction_computer import TransactionComputer from multiversx_sdk.wallet.keypair import KeyPair from multiversx_sdk.wallet.user_keys import UserSecretKey -from multiversx_sdk.core.transaction_computer import TransactionComputer - def test_create_keypair(): buffer_hex = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" @@ -43,7 +42,7 @@ def test_sign_and_verify_transaction(): gas_limit=50000, chain_id="local-testnet", version=1, - options=0 + options=0, ) buffer_hex = "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" @@ -54,5 +53,8 @@ def test_sign_and_verify_transaction(): serialized_tx = transaction_computer.compute_bytes_for_signing(tx) tx.signature = keypair.sign(serialized_tx) - assert tx.signature.hex() == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + assert ( + tx.signature.hex() + == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + ) assert keypair.verify(serialized_tx, tx.signature) diff --git a/multiversx_sdk/wallet/libraries/bls_facade.py b/multiversx_sdk/wallet/libraries/bls_facade.py index d9f793db..415aa9fc 100644 --- a/multiversx_sdk/wallet/libraries/bls_facade.py +++ b/multiversx_sdk/wallet/libraries/bls_facade.py @@ -4,8 +4,7 @@ from pathlib import Path from typing import Optional -from multiversx_sdk.wallet.errors import (LibraryNotFoundError, - UnsupportedOSError) +from multiversx_sdk.wallet.errors import LibraryNotFoundError, UnsupportedOSError class BLSFacade: @@ -35,10 +34,7 @@ def generate_public_key(self, private_key: bytes) -> bytes: def compute_message_signature(self, message: bytes, private_key: bytes) -> bytes: compute_message_signature_function = self._get_library().computeMessageSignature - output = compute_message_signature_function( - message.hex().encode(), - private_key.hex().encode() - ) + output = compute_message_signature_function(message.hex().encode(), private_key.hex().encode()) output_bytes = ctypes.string_at(output) signature_hex = output_bytes.decode() @@ -49,9 +45,7 @@ def verify_message_signature(self, public_key: bytes, message: bytes, signature: verify_message_signature_function = self._get_library().verifyMessageSignature output = verify_message_signature_function( - public_key.hex().encode(), - message.hex().encode(), - signature.hex().encode() + public_key.hex().encode(), message.hex().encode(), signature.hex().encode() ) output_int = ctypes.c_int(output) @@ -80,7 +74,11 @@ def _load_library(self) -> ctypes.CDLL: lib.computeMessageSignature.argtypes = [ctypes.c_char_p, ctypes.c_char_p] lib.computeMessageSignature.restype = ctypes.c_char_p - lib.verifyMessageSignature.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] + lib.verifyMessageSignature.argtypes = [ + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.c_char_p, + ] lib.verifyMessageSignature.restype = ctypes.c_int logging.info(f"Loaded library: {lib_path}") diff --git a/multiversx_sdk/wallet/libraries/bls_facade_test.py b/multiversx_sdk/wallet/libraries/bls_facade_test.py index 8d8f4c4e..8a776a97 100644 --- a/multiversx_sdk/wallet/libraries/bls_facade_test.py +++ b/multiversx_sdk/wallet/libraries/bls_facade_test.py @@ -5,11 +5,18 @@ def test_generate_public_key(): facade = BLSFacade() # With good input - public_key = facade.generate_public_key(bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247")) - assert public_key.hex() == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + public_key = facade.generate_public_key( + bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247") + ) + assert ( + public_key.hex() + == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ) # With bad input - public_key = facade.generate_public_key(bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd7742")) + public_key = facade.generate_public_key( + bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd7742") + ) assert public_key.hex() == "" @@ -19,15 +26,18 @@ def test_compute_message_signature(): # With good input signature = facade.compute_message_signature( message=b"hello", - private_key=bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247") + private_key=bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247"), ) - assert signature.hex() == "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + assert ( + signature.hex() + == "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ) # With bad input (bad key) signature = facade.compute_message_signature( message=b"hello", - private_key=bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd7742") + private_key=bytes.fromhex("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd7742"), ) assert signature.hex() == "" @@ -38,34 +48,50 @@ def test_verify_message_signature(): # With good input ok = facade.verify_message_signature( - public_key=bytes.fromhex("e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"), + public_key=bytes.fromhex( + "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ), message=b"hello", - signature=bytes.fromhex("84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + signature=bytes.fromhex( + "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ), ) assert ok # With altered signature ok = facade.verify_message_signature( - public_key=bytes.fromhex("e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"), + public_key=bytes.fromhex( + "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ), message=b"hello", - signature=bytes.fromhex("94fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + signature=bytes.fromhex( + "94fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ), ) # With altered message ok = facade.verify_message_signature( - public_key=bytes.fromhex("e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"), + public_key=bytes.fromhex( + "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ), message=b"helloWorld", - signature=bytes.fromhex("84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + signature=bytes.fromhex( + "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ), ) assert not ok # With bad public key ok = facade.verify_message_signature( - public_key=bytes.fromhex("badbad95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208"), + public_key=bytes.fromhex( + "badbad95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ), message=b"hello", - signature=bytes.fromhex("84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + signature=bytes.fromhex( + "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ), ) assert not ok diff --git a/multiversx_sdk/wallet/mnemonic.py b/multiversx_sdk/wallet/mnemonic.py index 2062b8ba..cdcd9391 100644 --- a/multiversx_sdk/wallet/mnemonic.py +++ b/multiversx_sdk/wallet/mnemonic.py @@ -22,7 +22,7 @@ def is_text_valid(cls, text: str) -> bool: return mnemonic.Mnemonic(BIP39_LANGUAGE).check(text) @classmethod - def generate(cls) -> 'Mnemonic': + def generate(cls) -> "Mnemonic": text = mnemonic.Mnemonic(BIP39_LANGUAGE).generate(strength=BIP39_STRENGTH) return Mnemonic(text) diff --git a/multiversx_sdk/wallet/mnemonic_test.py b/multiversx_sdk/wallet/mnemonic_test.py index 15d7ed9a..c6083d5f 100644 --- a/multiversx_sdk/wallet/mnemonic_test.py +++ b/multiversx_sdk/wallet/mnemonic_test.py @@ -17,7 +17,9 @@ def test_generate(): def test_derive_keys(): - mnemonic = Mnemonic("moral volcano peasant pass circle pen over picture flat shop clap goat never lyrics gather prepare woman film husband gravity behind test tiger improve") + mnemonic = Mnemonic( + "moral volcano peasant pass circle pen over picture flat shop clap goat never lyrics gather prepare woman film husband gravity behind test tiger improve" + ) assert mnemonic.derive_key(0).hex() == "413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9" assert mnemonic.derive_key(1).hex() == "b8ca6f8203fb4b545a8e83c5384da033c415db155b53fb5b8eba7ff5a039d639" assert mnemonic.derive_key(2).hex() == "e253a571ca153dc2aee845819f74bcc9773b0586edead15a94cb7235a5027436" @@ -33,12 +35,12 @@ def test_conversion(text: str, entropy_hex: str) -> None: test_conversion( text="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", - entropy_hex="00000000000000000000000000000000" + entropy_hex="00000000000000000000000000000000", ) test_conversion( text="moral volcano peasant pass circle pen over picture flat shop clap goat never lyrics gather prepare woman film husband gravity behind test tiger improve", - entropy_hex="8fbeb688d0529344e77d225898d4a73209510ad81d4ffceac9bfb30149bf387b" + entropy_hex="8fbeb688d0529344e77d225898d4a73209510ad81d4ffceac9bfb30149bf387b", ) with pytest.raises(ValueError): diff --git a/multiversx_sdk/wallet/pem_entry.py b/multiversx_sdk/wallet/pem_entry.py index 8a5aa779..e9e31f7a 100644 --- a/multiversx_sdk/wallet/pem_entry.py +++ b/multiversx_sdk/wallet/pem_entry.py @@ -9,12 +9,15 @@ def __init__(self, label: str, message: bytes) -> None: self.message: bytes = message @classmethod - def from_text_all(cls, pem_text: str) -> list['PemEntry']: + def from_text_all(cls, pem_text: str) -> list["PemEntry"]: lines = pem_text.splitlines() lines = _clean_lines(lines) - messages_lines = [list(message_lines) for is_next_entry, message_lines in itertools.groupby(lines, lambda line: "-----" in line) - if not is_next_entry] + messages_lines = [ + list(message_lines) + for is_next_entry, message_lines in itertools.groupby(lines, lambda line: "-----" in line) + if not is_next_entry + ] messages_base64 = ["".join(message_lines) for message_lines in messages_lines] labels = _parse_labels(lines) diff --git a/multiversx_sdk/wallet/pem_entry_test.py b/multiversx_sdk/wallet/pem_entry_test.py index 67fbec01..82e8a971 100644 --- a/multiversx_sdk/wallet/pem_entry_test.py +++ b/multiversx_sdk/wallet/pem_entry_test.py @@ -1,4 +1,3 @@ - from pathlib import Path from multiversx_sdk.wallet.constants import USER_SEED_LENGTH @@ -34,26 +33,41 @@ def test_from_text_all(): def test_from_text_all_for_validators(): text = (testwallets / "validatorKey00.pem").read_text() entry = PemEntry.from_text_all(text)[0] - assert entry.label == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + assert ( + entry.label + == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ) assert entry.message.hex() == "7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247" text = (testwallets / "multipleValidatorKeys.pem").read_text() entries = PemEntry.from_text_all(text) entry = entries[0] - assert entry.label == "f8910e47cf9464777c912e6390758bb39715fffcb861b184017920e4a807b42553f2f21e7f3914b81bcf58b66a72ab16d97013ae1cff807cefc977ef8cbf116258534b9e46d19528042d16ef8374404a89b184e0a4ee18c77c49e454d04eae8d" + assert ( + entry.label + == "f8910e47cf9464777c912e6390758bb39715fffcb861b184017920e4a807b42553f2f21e7f3914b81bcf58b66a72ab16d97013ae1cff807cefc977ef8cbf116258534b9e46d19528042d16ef8374404a89b184e0a4ee18c77c49e454d04eae8d" + ) assert entry.message.hex() == "7c19bf3a0c57cdd1fb08e4607cebaa3647d6b9261b4693f61e96e54b218d442a" entry = entries[1] - assert entry.label == "1b4e60e6d100cdf234d3427494dac55fbac49856cadc86bcb13a01b9bb05a0d9143e86c186c948e7ae9e52427c9523102efe9019a2a9c06db02993f2e3e6756576ae5a3ec7c235d548bc79de1a6990e1120ae435cb48f7fc436c9f9098b92a0d" + assert ( + entry.label + == "1b4e60e6d100cdf234d3427494dac55fbac49856cadc86bcb13a01b9bb05a0d9143e86c186c948e7ae9e52427c9523102efe9019a2a9c06db02993f2e3e6756576ae5a3ec7c235d548bc79de1a6990e1120ae435cb48f7fc436c9f9098b92a0d" + ) assert entry.message.hex() == "3034b1d58628a842984da0c70da0b5a251ebb2aebf51afc5b586e2839b5e5263" entry = entries[2] - assert entry.label == "e5dc552b4b170cdec4405ff8f9af20313bf0e2756d06c35877b6fbcfa6b354a7b3e2d439ea87999befb09a8fa1b3f014e57ec747bf738c4199338fcd4a87b373dd62f5c8329f1f5f245956bbb06685596a2e83dc38befa63e4a2b5c4ce408506" + assert ( + entry.label + == "e5dc552b4b170cdec4405ff8f9af20313bf0e2756d06c35877b6fbcfa6b354a7b3e2d439ea87999befb09a8fa1b3f014e57ec747bf738c4199338fcd4a87b373dd62f5c8329f1f5f245956bbb06685596a2e83dc38befa63e4a2b5c4ce408506" + ) assert entry.message.hex() == "de7e1b385edbb0e1e8f9fc25d91bd8eed71a1da7caab732e6b47a48042d8523d" entry = entries[3] - assert entry.label == "12773304cb718250edd89770cedcbf675ccdb7fe2b30bd3185ca65ffa0d516879768ed03f92e41a6e5bc5340b78a9d02655e3b727c79730ead791fb68eaa02b84e1be92a816a9604a1ab9a6d3874b638487e2145239438a4bafac3889348d405" + assert ( + entry.label + == "12773304cb718250edd89770cedcbf675ccdb7fe2b30bd3185ca65ffa0d516879768ed03f92e41a6e5bc5340b78a9d02655e3b727c79730ead791fb68eaa02b84e1be92a816a9604a1ab9a6d3874b638487e2145239438a4bafac3889348d405" + ) assert entry.message.hex() == "8ebeb07d296ad2529400b40687a741a135f8357f79f39fcb2894a6f9703a5816" diff --git a/multiversx_sdk/wallet/user_keys.py b/multiversx_sdk/wallet/user_keys.py index 0052001d..36cebe5b 100644 --- a/multiversx_sdk/wallet/user_keys.py +++ b/multiversx_sdk/wallet/user_keys.py @@ -3,10 +3,11 @@ import nacl.signing from multiversx_sdk.core.address import Address -from multiversx_sdk.wallet.constants import (USER_PUBKEY_LENGTH, - USER_SEED_LENGTH) -from multiversx_sdk.wallet.errors import (InvalidPublicKeyLengthError, - InvalidSecretKeyLengthError) +from multiversx_sdk.wallet.constants import USER_PUBKEY_LENGTH, USER_SEED_LENGTH +from multiversx_sdk.wallet.errors import ( + InvalidPublicKeyLengthError, + InvalidSecretKeyLengthError, +) class UserSecretKey: @@ -17,17 +18,17 @@ def __init__(self, buffer: bytes) -> None: self.buffer = buffer @classmethod - def generate(cls) -> 'UserSecretKey': + def generate(cls) -> "UserSecretKey": signing_key = nacl.signing.SigningKey.generate() secret_key = bytes(signing_key) return UserSecretKey(secret_key) @classmethod - def new_from_string(cls, buffer_hex: str) -> 'UserSecretKey': + def new_from_string(cls, buffer_hex: str) -> "UserSecretKey": buffer = bytes.fromhex(buffer_hex) return UserSecretKey(buffer) - def generate_public_key(self) -> 'UserPublicKey': + def generate_public_key(self) -> "UserPublicKey": public_key = bytes(nacl.signing.SigningKey(self.buffer).verify_key) return UserPublicKey(public_key) diff --git a/multiversx_sdk/wallet/user_pem.py b/multiversx_sdk/wallet/user_pem.py index fa919541..0f348475 100644 --- a/multiversx_sdk/wallet/user_pem.py +++ b/multiversx_sdk/wallet/user_pem.py @@ -12,21 +12,21 @@ def __init__(self, label: str, secret_key: UserSecretKey) -> None: self.public_key = secret_key.generate_public_key() @classmethod - def from_file(cls, path: Path, index: int = 0) -> 'UserPEM': + def from_file(cls, path: Path, index: int = 0) -> "UserPEM": return cls.from_file_all(path)[index] @classmethod - def from_file_all(cls, path: Path) -> list['UserPEM']: + def from_file_all(cls, path: Path) -> list["UserPEM"]: text = path.expanduser().resolve().read_text() return cls.from_text_all(text) @classmethod - def from_text(cls, text: str, index: int = 0) -> 'UserPEM': + def from_text(cls, text: str, index: int = 0) -> "UserPEM": items = cls.from_text_all(text) return items[index] @classmethod - def from_text_all(cls, text: str) -> list['UserPEM']: + def from_text_all(cls, text: str) -> list["UserPEM"]: entries = PemEntry.from_text_all(text) result_items: list[UserPEM] = [] diff --git a/multiversx_sdk/wallet/user_signer.py b/multiversx_sdk/wallet/user_signer.py index dd3183e8..aaae4273 100644 --- a/multiversx_sdk/wallet/user_signer.py +++ b/multiversx_sdk/wallet/user_signer.py @@ -15,17 +15,17 @@ def __init__(self, secret_key: UserSecretKey) -> None: self.secret_key = secret_key @classmethod - def from_pem_file(cls, path: Path, index: int = 0) -> 'UserSigner': + def from_pem_file(cls, path: Path, index: int = 0) -> "UserSigner": secret_key = UserPEM.from_file(path, index).secret_key return UserSigner(secret_key) @classmethod - def from_pem_file_all(cls, path: Path) -> list['UserSigner']: + def from_pem_file_all(cls, path: Path) -> list["UserSigner"]: users = UserPEM.from_file_all(path) return [UserSigner(user.secret_key) for user in users] @classmethod - def from_wallet(cls, path: Path, password: str) -> 'UserSigner': + def from_wallet(cls, path: Path, password: str) -> "UserSigner": secret_key = UserWallet.load_secret_key(path, password) return UserSigner(secret_key) diff --git a/multiversx_sdk/wallet/user_test.py b/multiversx_sdk/wallet/user_test.py index 7f11cbee..9889b71e 100644 --- a/multiversx_sdk/wallet/user_test.py +++ b/multiversx_sdk/wallet/user_test.py @@ -3,8 +3,13 @@ import pytest -from multiversx_sdk.core import (Address, Message, MessageComputer, - Transaction, TransactionComputer) +from multiversx_sdk.core import ( + Address, + Message, + MessageComputer, + Transaction, + TransactionComputer, +) from multiversx_sdk.wallet.crypto.randomness import Randomness from multiversx_sdk.wallet.user_keys import UserSecretKey from multiversx_sdk.wallet.user_pem import UserPEM @@ -27,9 +32,24 @@ def test_user_secret_key_create(): def test_user_secret_key_generate_public_key(): - assert UserSecretKey.new_from_string("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9").generate_public_key().hex() == "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" - assert UserSecretKey.new_from_string("b8ca6f8203fb4b545a8e83c5384da033c415db155b53fb5b8eba7ff5a039d639").generate_public_key().hex() == "8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" - assert UserSecretKey.new_from_string("e253a571ca153dc2aee845819f74bcc9773b0586edead15a94cb7235a5027436").generate_public_key().hex() == "b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba" + assert ( + UserSecretKey.new_from_string("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9") + .generate_public_key() + .hex() + == "0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1" + ) + assert ( + UserSecretKey.new_from_string("b8ca6f8203fb4b545a8e83c5384da033c415db155b53fb5b8eba7ff5a039d639") + .generate_public_key() + .hex() + == "8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8" + ) + assert ( + UserSecretKey.new_from_string("e253a571ca153dc2aee845819f74bcc9773b0586edead15a94cb7235a5027436") + .generate_public_key() + .hex() + == "b2a11555ce521e4944e09ab17549d85b487dcd26c84b5017a39e31a3670889ba" + ) def test_user_signer_from_pem_file(): @@ -47,32 +67,53 @@ def test_load_signers_from_pem(): signers = UserSigner.from_pem_file_all(testwallets / "multipleUserKeys.pem") assert len(signers) == 3 - assert Address(signers[0].get_pubkey().buffer, "erd").to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" - assert Address(signers[1].get_pubkey().buffer, "erd").to_bech32() == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" - assert Address(signers[2].get_pubkey().buffer, "erd").to_bech32() == "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" + assert ( + Address(signers[0].get_pubkey().buffer, "erd").to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) + assert ( + Address(signers[1].get_pubkey().buffer, "erd").to_bech32() + == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" + ) + assert ( + Address(signers[2].get_pubkey().buffer, "erd").to_bech32() + == "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" + ) def test_user_wallet_to_keyfile_object_using_known_test_wallets_with_their_randomness(): alice_secret_key = UserSecretKey.new_from_string("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9") - alice_wallet = UserWallet.from_secret_key(alice_secret_key, "password", Randomness( - salt=bytes.fromhex("4903bd0e7880baa04fc4f886518ac5c672cdc745a6bd13dcec2b6c12e9bffe8d"), - iv=bytes.fromhex("033182afaa1ebaafcde9ccc68a5eac31"), - id="0dc10c02-b59b-4bac-9710-6b2cfa4284ba" - )) + alice_wallet = UserWallet.from_secret_key( + alice_secret_key, + "password", + Randomness( + salt=bytes.fromhex("4903bd0e7880baa04fc4f886518ac5c672cdc745a6bd13dcec2b6c12e9bffe8d"), + iv=bytes.fromhex("033182afaa1ebaafcde9ccc68a5eac31"), + id="0dc10c02-b59b-4bac-9710-6b2cfa4284ba", + ), + ) bob_secret_key = UserSecretKey.new_from_string("b8ca6f8203fb4b545a8e83c5384da033c415db155b53fb5b8eba7ff5a039d639") - bob_wallet = UserWallet.from_secret_key(bob_secret_key, "password", Randomness( - salt=bytes.fromhex("18304455ac2dbe2a2018bda162bd03ef95b81622e99d8275c34a6d5e6932a68b"), - iv=bytes.fromhex("18378411e31f6c4e99f1435d9ab82831"), - id="85fdc8a7-7119-479d-b7fb-ab4413ed038d" - )) + bob_wallet = UserWallet.from_secret_key( + bob_secret_key, + "password", + Randomness( + salt=bytes.fromhex("18304455ac2dbe2a2018bda162bd03ef95b81622e99d8275c34a6d5e6932a68b"), + iv=bytes.fromhex("18378411e31f6c4e99f1435d9ab82831"), + id="85fdc8a7-7119-479d-b7fb-ab4413ed038d", + ), + ) carol_secret_key = UserSecretKey.new_from_string("e253a571ca153dc2aee845819f74bcc9773b0586edead15a94cb7235a5027436") - carol_wallet = UserWallet.from_secret_key(carol_secret_key, "password", Randomness( - salt=bytes.fromhex("4f2f5530ce28dc0210962589b908f52714f75c8fb79ff18bdd0024c43c7a220b"), - iv=bytes.fromhex("258ed2b4dc506b4dc9d274b0449b0eb0"), - id="65894f35-d142-41d2-9335-6ad02e0ed0be" - )) + carol_wallet = UserWallet.from_secret_key( + carol_secret_key, + "password", + Randomness( + salt=bytes.fromhex("4f2f5530ce28dc0210962589b908f52714f75c8fb79ff18bdd0024c43c7a220b"), + iv=bytes.fromhex("258ed2b4dc506b4dc9d274b0449b0eb0"), + id="65894f35-d142-41d2-9335-6ad02e0ed0be", + ), + ) alice_saved_path = testwallets / "alice.saved.json" bob_saved_path = testwallets / "bob.saved.json" @@ -126,27 +167,40 @@ def test_sign_transaction(): gas_limit=50000, chain_id="local-testnet", version=1, - options=0 + options=0, ) signer = UserSigner.from_pem_file(testwallets / "alice.pem") - verifier = UserVerifier.from_address(Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")) + verifier = UserVerifier.from_address( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") + ) transaction_computer = TransactionComputer() tx.signature = signer.sign(transaction_computer.compute_bytes_for_signing(tx)) - assert tx.signature.hex() == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + assert ( + tx.signature.hex() + == "b56769014f2bdc5cf9fc4a05356807d71fcf8775c819b0f1b0964625b679c918ffa64862313bfef86f99b38cb84fcdb16fa33ad6eb565276616723405cd8f109" + ) assert verifier.verify(transaction_computer.compute_bytes_for_signing(tx), tx.signature) def test_sign_message(): - message = Message("hello".encode(), address=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")) + message = Message( + "hello".encode(), + address=Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"), + ) message_computer = MessageComputer() signer = UserSigner.from_pem_file(testwallets / "alice.pem") - verifier = UserVerifier.from_address(Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th")) + verifier = UserVerifier.from_address( + Address.new_from_bech32("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th") + ) message.signature = signer.sign(message_computer.compute_bytes_for_signing(message)) - assert message.signature.hex() == "561bc58f1dc6b10de208b2d2c22c9a474ea5e8cabb59c3d3ce06bbda21cc46454aa71a85d5a60442bd7784effa2e062fcb8fb421c521f898abf7f5ec165e5d0f" + assert ( + message.signature.hex() + == "561bc58f1dc6b10de208b2d2c22c9a474ea5e8cabb59c3d3ce06bbda21cc46454aa71a85d5a60442bd7784effa2e062fcb8fb421c521f898abf7f5ec165e5d0f" + ) assert verifier.verify(message_computer.compute_bytes_for_signing(message), message.signature) @@ -193,7 +247,7 @@ def test_create_keystore_with_mnemonic_with_randomness(): randomness = Randomness( id="5b448dbc-5c72-4d83-8038-938b1f8dff19", iv=bytes.fromhex("2da5620906634972d9a623bc249d63d4"), - salt=bytes.fromhex("aa9e0ba6b188703071a582c10e5331f2756279feb0e2768f1ba0fd38ec77f035") + salt=bytes.fromhex("aa9e0ba6b188703071a582c10e5331f2756279feb0e2768f1ba0fd38ec77f035"), ) wallet = UserWallet.from_mnemonic(DUMMY_MNEMONIC, "password", randomness) @@ -205,9 +259,18 @@ def test_create_keystore_with_mnemonic_with_randomness(): def test_load_secret_key_with_mnemonic(): keystore_path = testwallets / "withDummyMnemonic.json" - assert UserWallet.load_secret_key(keystore_path, "password", 1).generate_public_key().to_address("erd").to_bech32() == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" - assert UserWallet.load_secret_key(keystore_path, "password", 2).generate_public_key().to_address("erd").to_bech32() == "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" - assert UserWallet.load_secret_key(keystore_path, "password", 0).generate_public_key().to_address("erd").to_bech32() == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + assert ( + UserWallet.load_secret_key(keystore_path, "password", 1).generate_public_key().to_address("erd").to_bech32() + == "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx" + ) + assert ( + UserWallet.load_secret_key(keystore_path, "password", 2).generate_public_key().to_address("erd").to_bech32() + == "erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8" + ) + assert ( + UserWallet.load_secret_key(keystore_path, "password", 0).generate_public_key().to_address("erd").to_bech32() + == "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th" + ) def test_decrypt_secret_key_with_keystore_mnemonic(): diff --git a/multiversx_sdk/wallet/user_verifer.py b/multiversx_sdk/wallet/user_verifer.py index 76c1f741..9c4df21f 100644 --- a/multiversx_sdk/wallet/user_verifer.py +++ b/multiversx_sdk/wallet/user_verifer.py @@ -7,7 +7,7 @@ def __init__(self, public_key: UserPublicKey) -> None: self.public_key = public_key @classmethod - def from_address(cls, address: Address) -> 'UserVerifier': + def from_address(cls, address: Address) -> "UserVerifier": buffer: bytes = address.get_public_key() public_key = UserPublicKey(buffer) return UserVerifier(public_key) diff --git a/multiversx_sdk/wallet/user_wallet.py b/multiversx_sdk/wallet/user_wallet.py index d23c6e5d..6c0eee8f 100644 --- a/multiversx_sdk/wallet/user_wallet.py +++ b/multiversx_sdk/wallet/user_wallet.py @@ -4,8 +4,7 @@ from pathlib import Path from typing import Any, Optional, Union -from multiversx_sdk.wallet.crypto import (EncryptedData, Randomness, decryptor, - encryptor) +from multiversx_sdk.wallet.crypto import EncryptedData, Randomness, decryptor, encryptor from multiversx_sdk.wallet.interfaces import IRandomness from multiversx_sdk.wallet.mnemonic import Mnemonic from multiversx_sdk.wallet.user_keys import UserPublicKey, UserSecretKey @@ -17,7 +16,12 @@ class UserWalletKind(str, Enum): class UserWallet: - def __init__(self, kind: str, encrypted_data: EncryptedData, public_key_when_kind_is_secret_key: Optional[UserPublicKey] = None) -> None: + def __init__( + self, + kind: str, + encrypted_data: EncryptedData, + public_key_when_kind_is_secret_key: Optional[UserPublicKey] = None, + ) -> None: """ Do not use this constructor directly. Use the static methods from_secret_key() and from_mnemonic() instead. """ @@ -26,7 +30,12 @@ def __init__(self, kind: str, encrypted_data: EncryptedData, public_key_when_kin self.public_key_when_kind_is_secret_key = public_key_when_kind_is_secret_key @classmethod - def from_secret_key(cls, secret_key: UserSecretKey, password: str, randomness: Union[IRandomness, None] = None) -> 'UserWallet': + def from_secret_key( + cls, + secret_key: UserSecretKey, + password: str, + randomness: Union[IRandomness, None] = None, + ) -> "UserWallet": randomness = randomness or Randomness() public_key = secret_key.generate_public_key() @@ -36,21 +45,18 @@ def from_secret_key(cls, secret_key: UserSecretKey, password: str, randomness: U return cls( kind=UserWalletKind.SECRET_KEY.value, encrypted_data=encrypted_data, - public_key_when_kind_is_secret_key=public_key + public_key_when_kind_is_secret_key=public_key, ) @classmethod - def from_mnemonic(cls, mnemonic: str, password: str, randomness: Union[IRandomness, None] = None) -> 'UserWallet': + def from_mnemonic(cls, mnemonic: str, password: str, randomness: Union[IRandomness, None] = None) -> "UserWallet": randomness = randomness or Randomness() Mnemonic.assert_text_is_valid(mnemonic) data = mnemonic.encode() encrypted_data = encryptor.encrypt(data, password, randomness) - return cls( - kind=UserWalletKind.MNEMONIC.value, - encrypted_data=encrypted_data - ) + return cls(kind=UserWalletKind.MNEMONIC.value, encrypted_data=encrypted_data) @classmethod def decrypt_secret_key(cls, keyfile_object: dict[str, Any], password: str) -> UserSecretKey: @@ -61,13 +67,13 @@ def decrypt_secret_key(cls, keyfile_object: dict[str, Any], password: str) -> Us encrypted_data = EncryptedData.from_keyfile_object(keyfile_object) buffer = decryptor.decrypt(encrypted_data, password) - buffer = buffer.rjust(32, b'\x00') + buffer = buffer.rjust(32, b"\x00") seed = buffer[:32] return UserSecretKey(seed) @classmethod def decrypt_mnemonic(cls, keyfile_object: dict[str, Any], password: str) -> Mnemonic: - if keyfile_object['kind'] != UserWalletKind.MNEMONIC.value: + if keyfile_object["kind"] != UserWalletKind.MNEMONIC.value: raise Exception(f"Expected kind to be {UserWalletKind.MNEMONIC.value}, but it was {keyfile_object['kind']}") encrypted_data = EncryptedData.from_keyfile_object(keyfile_object) @@ -76,7 +82,7 @@ def decrypt_mnemonic(cls, keyfile_object: dict[str, Any], password: str) -> Mnem return mnemonic @classmethod - def load_secret_key(cls, path: Path, password: str, address_index: Optional[int] = None) -> 'UserSecretKey': + def load_secret_key(cls, path: Path, password: str, address_index: Optional[int] = None) -> "UserSecretKey": """ Loads a secret key from a keystore file. @@ -128,7 +134,7 @@ def _to_dict_when_kind_is_secret_key(self, address_hrp: Optional[str] = None) -> "id": self.encrypted_data.id, "address": self.public_key_when_kind_is_secret_key.hex(), "bech32": self.public_key_when_kind_is_secret_key.to_address(address_hrp).to_bech32(), - "crypto": crypto_section + "crypto": crypto_section, } return envelope @@ -140,7 +146,7 @@ def _to_dict_when_kind_is_mnemonic(self) -> dict[str, Any]: "version": self.encrypted_data.version, "kind": self.kind, "id": self.encrypted_data.id, - "crypto": crypto_section + "crypto": crypto_section, } return envelope @@ -156,7 +162,7 @@ def _get_crypto_section_as_dict(self) -> dict[str, Any]: "salt": self.encrypted_data.salt, "n": self.encrypted_data.kdfparams.n, "r": self.encrypted_data.kdfparams.r, - "p": self.encrypted_data.kdfparams.p + "p": self.encrypted_data.kdfparams.p, }, - "mac": self.encrypted_data.mac + "mac": self.encrypted_data.mac, } diff --git a/multiversx_sdk/wallet/validator_keys.py b/multiversx_sdk/wallet/validator_keys.py index ede53ce9..e50abf2b 100644 --- a/multiversx_sdk/wallet/validator_keys.py +++ b/multiversx_sdk/wallet/validator_keys.py @@ -1,5 +1,7 @@ -from multiversx_sdk.wallet.constants import (VALIDATOR_PUBKEY_LENGTH, - VALIDATOR_SECRETKEY_LENGTH) +from multiversx_sdk.wallet.constants import ( + VALIDATOR_PUBKEY_LENGTH, + VALIDATOR_SECRETKEY_LENGTH, +) from multiversx_sdk.wallet.errors import InvalidSecretKeyLengthError from multiversx_sdk.wallet.libraries.bls_facade import BLSFacade @@ -12,16 +14,16 @@ def __init__(self, buffer: bytes) -> None: self.buffer = buffer @classmethod - def generate(cls) -> 'ValidatorSecretKey': + def generate(cls) -> "ValidatorSecretKey": secret_key_bytes = BLSFacade().generate_private_key() return ValidatorSecretKey(secret_key_bytes) @classmethod - def from_string(cls, buffer_hex: str) -> 'ValidatorSecretKey': + def from_string(cls, buffer_hex: str) -> "ValidatorSecretKey": buffer = bytes.fromhex(buffer_hex) return ValidatorSecretKey(buffer) - def generate_public_key(self) -> 'ValidatorPublicKey': + def generate_public_key(self) -> "ValidatorPublicKey": public_key_bytes = BLSFacade().generate_public_key(self.buffer) return ValidatorPublicKey(public_key_bytes) @@ -47,7 +49,7 @@ def __init__(self, buffer: bytes) -> None: self.buffer = buffer @classmethod - def from_string(cls, buffer_hex: str) -> 'ValidatorPublicKey': + def from_string(cls, buffer_hex: str) -> "ValidatorPublicKey": buffer = bytes.fromhex(buffer_hex) return ValidatorPublicKey(buffer) diff --git a/multiversx_sdk/wallet/validator_pem.py b/multiversx_sdk/wallet/validator_pem.py index 5d389c9e..8c0e11fa 100644 --- a/multiversx_sdk/wallet/validator_pem.py +++ b/multiversx_sdk/wallet/validator_pem.py @@ -10,21 +10,21 @@ def __init__(self, label: str, secret_key: ValidatorSecretKey) -> None: self.secret_key = secret_key @classmethod - def from_file(cls, path: Path, index: int = 0) -> 'ValidatorPEM': + def from_file(cls, path: Path, index: int = 0) -> "ValidatorPEM": return cls.from_file_all(path)[index] @classmethod - def from_file_all(cls, path: Path) -> list['ValidatorPEM']: + def from_file_all(cls, path: Path) -> list["ValidatorPEM"]: text = path.expanduser().resolve().read_text() return cls.from_text_all(text) @classmethod - def from_text(cls, text: str, index: int = 0) -> 'ValidatorPEM': + def from_text(cls, text: str, index: int = 0) -> "ValidatorPEM": items = cls.from_text_all(text) return items[index] @classmethod - def from_text_all(cls, text: str) -> list['ValidatorPEM']: + def from_text_all(cls, text: str) -> list["ValidatorPEM"]: entries = PemEntry.from_text_all(text) result_items: list[ValidatorPEM] = [] diff --git a/multiversx_sdk/wallet/validator_signer.py b/multiversx_sdk/wallet/validator_signer.py index 26905c5e..1d65b751 100644 --- a/multiversx_sdk/wallet/validator_signer.py +++ b/multiversx_sdk/wallet/validator_signer.py @@ -1,8 +1,7 @@ from pathlib import Path from multiversx_sdk.wallet.errors import CannotSignError -from multiversx_sdk.wallet.validator_keys import (ValidatorPublicKey, - ValidatorSecretKey) +from multiversx_sdk.wallet.validator_keys import ValidatorPublicKey, ValidatorSecretKey from multiversx_sdk.wallet.validator_pem import ValidatorPEM @@ -15,7 +14,7 @@ def __init__(self, secret_key: ValidatorSecretKey) -> None: self.secret_key = secret_key @classmethod - def from_pem_file(cls, path: Path, index: int = 0) -> 'ValidatorSigner': + def from_pem_file(cls, path: Path, index: int = 0) -> "ValidatorSigner": secret_key = ValidatorPEM.from_file(path, index).secret_key return ValidatorSigner(secret_key) diff --git a/multiversx_sdk/wallet/validator_test.py b/multiversx_sdk/wallet/validator_test.py index 8e6a161e..fca5cf71 100644 --- a/multiversx_sdk/wallet/validator_test.py +++ b/multiversx_sdk/wallet/validator_test.py @@ -10,25 +10,39 @@ def test_validator_secret_key_generate_public_key(): - assert ValidatorSecretKey.from_string("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247").generate_public_key().hex() == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + assert ( + ValidatorSecretKey.from_string("7cff99bd671502db7d15bc8abc0c9a804fb925406fbdd50f1e4c17a4cd774247") + .generate_public_key() + .hex() + == "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ) def test_sign_message(): signer = ValidatorSigner.from_pem_file(testwallets / "validatorKey00.pem") message = b"hello" signature = signer.sign(message) - assert signature.hex() == "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + assert ( + signature.hex() + == "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ) def test_verify_message(): - verifier = ValidatorVerifier.from_string("e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208") + verifier = ValidatorVerifier.from_string( + "e7beaa95b3877f47348df4dd1cb578a4f7cabf7a20bfeefe5cdd263878ff132b765e04fef6f40c93512b666c47ed7719b8902f6c922c04247989b7137e837cc81a62e54712471c97a2ddab75aa9c2f58f813ed4c0fa722bde0ab718bff382208" + ) message = b"hello" - signature = bytes.fromhex("84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + signature = bytes.fromhex( + "84fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ) assert verifier.verify(message, signature) - invalid_signature = bytes.fromhex("94fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86") + invalid_signature = bytes.fromhex( + "94fd0a3a9d4f1ea2d4b40c6da67f9b786284a1c3895b7253fec7311597cda3f757862bb0690a92a13ce612c33889fd86" + ) assert verifier.verify(message, invalid_signature) is False diff --git a/multiversx_sdk/wallet/validator_verifier.py b/multiversx_sdk/wallet/validator_verifier.py index a2a9cf92..8c421d09 100644 --- a/multiversx_sdk/wallet/validator_verifier.py +++ b/multiversx_sdk/wallet/validator_verifier.py @@ -6,7 +6,7 @@ def __init__(self, public_key: ValidatorPublicKey) -> None: self.public_key = public_key @classmethod - def from_string(cls, buffer_hex: str) -> 'ValidatorVerifier': + def from_string(cls, buffer_hex: str) -> "ValidatorVerifier": public_key = ValidatorPublicKey.from_string(buffer_hex) return ValidatorVerifier(public_key)