From 101e24e2087378ec674b070de7bcc836b74dc449 Mon Sep 17 00:00:00 2001 From: dosi Date: Thu, 28 Aug 2025 14:47:38 +0300 Subject: [PATCH 1/7] feat: implement FreezeTransaction Signed-off-by: dosi --- .../system/freeze_transaction.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/hiero_sdk_python/system/freeze_transaction.py diff --git a/src/hiero_sdk_python/system/freeze_transaction.py b/src/hiero_sdk_python/system/freeze_transaction.py new file mode 100644 index 000000000..53f4a5a0b --- /dev/null +++ b/src/hiero_sdk_python/system/freeze_transaction.py @@ -0,0 +1,159 @@ +""" +FreezeTransaction class for freezing the network. +""" + +from typing import Optional + +from hiero_sdk_python.channels import _Channel +from hiero_sdk_python.executable import _Method +from hiero_sdk_python.file.file_id import FileId +from hiero_sdk_python.hapi.services.freeze_pb2 import FreezeTransactionBody +from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import ( + SchedulableTransactionBody, +) +from hiero_sdk_python.system.freeze_type import FreezeType +from hiero_sdk_python.timestamp import Timestamp +from hiero_sdk_python.transaction.transaction import Transaction + + +class FreezeTransaction(Transaction): + """ + Represents a freeze transaction on the network. + + This transaction freezes the network with the specified parameters including + start_time, file_id, file_hash, and freeze_type. + + Inherits from the base Transaction class and implements the required methods + to build and execute a freeze transaction. + """ + + def __init__( + self, + start_time: Optional[Timestamp] = None, + file_id: Optional[FileId] = None, + file_hash: Optional[bytes] = None, + freeze_type: Optional[FreezeType] = None, + ): + """ + Initializes a new FreezeTransaction instance with the specified parameters. + + Args: + start_time (Optional[Timestamp]): The start time for the freeze. + file_id (Optional[FileId]): The file ID containing the upgrade data. + file_hash (Optional[bytes]): Hash of the file for verification. + freeze_type (Optional[FreezeType]): The type of freeze to perform. + """ + super().__init__() + self.start_time: Optional[Timestamp] = start_time + self.file_id: Optional[FileId] = file_id + self.file_hash: Optional[bytes] = file_hash + self.freeze_type: Optional[FreezeType] = freeze_type + + def set_start_time(self, start_time: Optional[Timestamp]) -> "FreezeTransaction": + """ + Sets the start time for this freeze transaction. + + Args: + start_time (Optional[Timestamp]): The start time for the freeze. + + Returns: + FreezeTransaction: This transaction instance. + """ + self._require_not_frozen() + self.start_time = start_time + return self + + def set_file_id(self, file_id: Optional[FileId]) -> "FreezeTransaction": + """ + Sets the file ID for this freeze transaction. + + Args: + file_id (Optional[FileId]): The file ID containing the upgrade data. + + Returns: + FreezeTransaction: This transaction instance. + """ + self._require_not_frozen() + self.file_id = file_id + return self + + def set_file_hash(self, file_hash: Optional[bytes]) -> "FreezeTransaction": + """ + Sets the file hash for this freeze transaction. + + Args: + file_hash (Optional[bytes]): Hash of the file for verification. + + Returns: + FreezeTransaction: This transaction instance. + """ + self._require_not_frozen() + self.file_hash = file_hash + return self + + def set_freeze_type(self, freeze_type: Optional[FreezeType]) -> "FreezeTransaction": + """ + Sets the freeze type for this freeze transaction. + + Args: + freeze_type (Optional[FreezeType]): The type of freeze to perform. + + Returns: + FreezeTransaction: This transaction instance. + """ + self._require_not_frozen() + self.freeze_type = freeze_type + return self + + def _build_proto_body(self) -> FreezeTransactionBody: + """ + Returns the protobuf body for the freeze transaction. + + Returns: + FreezeTransactionBody: The protobuf body for this transaction. + """ + return FreezeTransactionBody( + start_time=self.start_time._to_protobuf() if self.start_time else None, + update_file=self.file_id._to_proto() if self.file_id else None, + file_hash=self.file_hash, + freeze_type=self.freeze_type._to_proto() if self.freeze_type else None, + ) + + def build_transaction_body(self): + """ + Builds the transaction body for this freeze transaction. + + Returns: + TransactionBody: The built transaction body. + """ + freeze_body = self._build_proto_body() + transaction_body = self.build_base_transaction_body() + transaction_body.freeze.CopyFrom(freeze_body) + return transaction_body + + def build_scheduled_body(self) -> SchedulableTransactionBody: + """ + Builds the scheduled transaction body for this freeze transaction. + + Returns: + SchedulableTransactionBody: The schedulable transaction body. + """ + freeze_body = self._build_proto_body() + schedulable_body = self.build_base_scheduled_body() + schedulable_body.freeze.CopyFrom(freeze_body) + return schedulable_body + + def _get_method(self, channel: _Channel) -> _Method: + """ + Gets the method to execute the freeze transaction. + + This internal method returns a _Method object containing the appropriate gRPC + function to call when executing this transaction on the Hedera network. + + Args: + channel (_Channel): The channel containing service stubs + + Returns: + _Method: An object containing the transaction function to freeze the network. + """ + return _Method(transaction_func=channel.freeze.freeze, query_func=None) From ea94da225e6f62e8c28cc504f9b814cef187cf06 Mon Sep 17 00:00:00 2001 From: dosi Date: Thu, 28 Aug 2025 15:08:26 +0300 Subject: [PATCH 2/7] feat: add FreezeType Signed-off-by: dosi --- src/hiero_sdk_python/system/freeze_type.py | 79 ++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/hiero_sdk_python/system/freeze_type.py diff --git a/src/hiero_sdk_python/system/freeze_type.py b/src/hiero_sdk_python/system/freeze_type.py new file mode 100644 index 000000000..2b39a67d5 --- /dev/null +++ b/src/hiero_sdk_python/system/freeze_type.py @@ -0,0 +1,79 @@ +""" +Defines FreezeType enum for representing freeze types +""" +from enum import Enum + +from hiero_sdk_python.hapi.services.freeze_type_pb2 import ( + FreezeType as proto_FreezeType, +) + + +class FreezeType(Enum): + """ + Freeze type: + + • UNKNOWN_FREEZE_TYPE - not applicable + • FREEZE_ONLY - Freeze only + • PREPARE_UPGRADE - Prepare upgrade + • FREEZE_UPGRADE - Freeze upgrade + • FREEZE_ABORT - Freeze abort + • TELEMETRY_UPGRADE - Telemetry upgrade + """ + + UNKNOWN_FREEZE_TYPE = 0 + FREEZE_ONLY = 1 + PREPARE_UPGRADE = 2 + FREEZE_UPGRADE = 3 + FREEZE_ABORT = 4 + TELEMETRY_UPGRADE = 5 + + @staticmethod + def _from_proto(proto_obj: proto_FreezeType): + """ + Converts a protobuf FreezeType to a FreezeType enum. + + Args: + proto_obj (proto_FreezeType): The protobuf FreezeType object. + + Returns: + FreezeType: The corresponding FreezeType enum value. + """ + if proto_obj == proto_FreezeType.FREEZE_ONLY: + return FreezeType.FREEZE_ONLY + elif proto_obj == proto_FreezeType.PREPARE_UPGRADE: + return FreezeType.PREPARE_UPGRADE + elif proto_obj == proto_FreezeType.FREEZE_UPGRADE: + return FreezeType.FREEZE_UPGRADE + elif proto_obj == proto_FreezeType.FREEZE_ABORT: + return FreezeType.FREEZE_ABORT + elif proto_obj == proto_FreezeType.TELEMETRY_UPGRADE: + return FreezeType.TELEMETRY_UPGRADE + return FreezeType.UNKNOWN_FREEZE_TYPE + + def _to_proto(self) -> proto_FreezeType: + """ + Converts a FreezeType enum to a protobuf FreezeType object. + + Args: + self (FreezeType): The FreezeType enum value. + + Returns: + proto_FreezeType: The corresponding protobuf FreezeType object. + """ + if self == FreezeType.FREEZE_ONLY: + return proto_FreezeType.FREEZE_ONLY + elif self == FreezeType.PREPARE_UPGRADE: + return proto_FreezeType.PREPARE_UPGRADE + elif self == FreezeType.FREEZE_UPGRADE: + return proto_FreezeType.FREEZE_UPGRADE + elif self == FreezeType.FREEZE_ABORT: + return proto_FreezeType.FREEZE_ABORT + elif self == FreezeType.TELEMETRY_UPGRADE: + return proto_FreezeType.TELEMETRY_UPGRADE + return proto_FreezeType.UNKNOWN_FREEZE_TYPE + + def __eq__(self, other): + if isinstance(other, FreezeType): + return self.value == other.value + elif isinstance(other, int): + return self.value == other From 228ed9e1fcb637a4a95d20c6248890d638f3d018 Mon Sep 17 00:00:00 2001 From: dosi Date: Sat, 6 Sep 2025 01:30:00 +0300 Subject: [PATCH 3/7] test: freeze type Signed-off-by: dosi --- tests/unit/test_freeze_type.py | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/unit/test_freeze_type.py diff --git a/tests/unit/test_freeze_type.py b/tests/unit/test_freeze_type.py new file mode 100644 index 000000000..58110dc14 --- /dev/null +++ b/tests/unit/test_freeze_type.py @@ -0,0 +1,95 @@ +""" +Test cases for the FreezeType enum class. +""" + +from unittest.mock import MagicMock + +import pytest + +from hiero_sdk_python.hapi.services.freeze_type_pb2 import ( + FreezeType as proto_FreezeType, +) +from hiero_sdk_python.system.freeze_type import FreezeType + +pytestmark = pytest.mark.unit + + +def test_freeze_type_values(): + """Test that FreezeType enum has correct values.""" + assert FreezeType.UNKNOWN_FREEZE_TYPE.value == 0 + assert FreezeType.FREEZE_ONLY.value == 1 + assert FreezeType.PREPARE_UPGRADE.value == 2 + assert FreezeType.FREEZE_UPGRADE.value == 3 + assert FreezeType.FREEZE_ABORT.value == 4 + assert FreezeType.TELEMETRY_UPGRADE.value == 5 + + +def test_from_proto_all_types(): + """Test _from_proto method with all freeze types.""" + test_cases = [ + (proto_FreezeType.FREEZE_ONLY, FreezeType.FREEZE_ONLY), + (proto_FreezeType.PREPARE_UPGRADE, FreezeType.PREPARE_UPGRADE), + (proto_FreezeType.FREEZE_UPGRADE, FreezeType.FREEZE_UPGRADE), + (proto_FreezeType.FREEZE_ABORT, FreezeType.FREEZE_ABORT), + (proto_FreezeType.TELEMETRY_UPGRADE, FreezeType.TELEMETRY_UPGRADE), + (proto_FreezeType.UNKNOWN_FREEZE_TYPE, FreezeType.UNKNOWN_FREEZE_TYPE), + ] + + for proto_type, expected in test_cases: + result = FreezeType._from_proto(proto_type) + assert result == expected + + +def test_from_proto_invalid_value(): + """Test _from_proto method with invalid proto value returns UNKNOWN_FREEZE_TYPE.""" + mock_proto = MagicMock() + mock_proto.__eq__ = lambda self, other: False + + result = FreezeType._from_proto(mock_proto) + assert result == FreezeType.UNKNOWN_FREEZE_TYPE + + +def test_to_proto_all_types(): + """Test _to_proto method with all freeze types.""" + test_cases = [ + (FreezeType.FREEZE_ONLY, proto_FreezeType.FREEZE_ONLY), + (FreezeType.PREPARE_UPGRADE, proto_FreezeType.PREPARE_UPGRADE), + (FreezeType.FREEZE_UPGRADE, proto_FreezeType.FREEZE_UPGRADE), + (FreezeType.FREEZE_ABORT, proto_FreezeType.FREEZE_ABORT), + (FreezeType.TELEMETRY_UPGRADE, proto_FreezeType.TELEMETRY_UPGRADE), + (FreezeType.UNKNOWN_FREEZE_TYPE, proto_FreezeType.UNKNOWN_FREEZE_TYPE), + ] + + for freeze_type, expected in test_cases: + proto_result = freeze_type._to_proto() + assert proto_result == expected + + +def test_eq(): + """Test __eq__ method for FreezeType.""" + assert FreezeType.FREEZE_ONLY == FreezeType.FREEZE_ONLY + assert FreezeType.FREEZE_ONLY != FreezeType.PREPARE_UPGRADE + + assert FreezeType.FREEZE_ONLY == 1 + assert FreezeType.PREPARE_UPGRADE == 2 + assert FreezeType.FREEZE_ONLY != 0 + + assert FreezeType.FREEZE_ONLY != "FREEZE_ONLY" + assert FreezeType.FREEZE_ONLY is not None + + +def test_round_trip_conversion(): + """Test round-trip conversion from FreezeType to proto and back.""" + freeze_types = [ + FreezeType.UNKNOWN_FREEZE_TYPE, + FreezeType.FREEZE_ONLY, + FreezeType.PREPARE_UPGRADE, + FreezeType.FREEZE_UPGRADE, + FreezeType.FREEZE_ABORT, + FreezeType.TELEMETRY_UPGRADE, + ] + + for freeze_type in freeze_types: + proto_obj = freeze_type._to_proto() + converted_back = FreezeType._from_proto(proto_obj) + assert converted_back == freeze_type From 9f1359df8eb92a7d9d7d8a116be071840f428187 Mon Sep 17 00:00:00 2001 From: dosi Date: Fri, 12 Sep 2025 10:07:57 +0300 Subject: [PATCH 4/7] test: add freeze transaction unit tests Signed-off-by: dosi --- tests/unit/test_freeze_transaction.py | 290 ++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 tests/unit/test_freeze_transaction.py diff --git a/tests/unit/test_freeze_transaction.py b/tests/unit/test_freeze_transaction.py new file mode 100644 index 000000000..f359154e2 --- /dev/null +++ b/tests/unit/test_freeze_transaction.py @@ -0,0 +1,290 @@ +""" +Test cases for the FreezeTransaction class. +""" + +from unittest.mock import MagicMock + +import pytest + +from hiero_sdk_python.file.file_id import FileId +from hiero_sdk_python.hapi.services.freeze_type_pb2 import ( + FreezeType as proto_FreezeType, +) +from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import ( + SchedulableTransactionBody, +) +from hiero_sdk_python.system.freeze_transaction import FreezeTransaction +from hiero_sdk_python.system.freeze_type import FreezeType +from hiero_sdk_python.timestamp import Timestamp + +pytestmark = pytest.mark.unit + + +@pytest.fixture +def freeze_params(): + """Fixture for freeze transaction parameters.""" + return { + "start_time": Timestamp(1640995200, 0), + "file_id": FileId(0, 0, 123), + "file_hash": b"test-file-hash", + "freeze_type": FreezeType.FREEZE_ONLY, + } + + +def test_constructor_with_parameters(freeze_params): + """Test creating a freeze transaction with constructor parameters.""" + freeze_tx = FreezeTransaction( + start_time=freeze_params["start_time"], + file_id=freeze_params["file_id"], + file_hash=freeze_params["file_hash"], + freeze_type=freeze_params["freeze_type"], + ) + + assert freeze_tx.start_time == freeze_params["start_time"] + assert freeze_tx.file_id == freeze_params["file_id"] + assert freeze_tx.file_hash == freeze_params["file_hash"] + assert freeze_tx.freeze_type == freeze_params["freeze_type"] + + +def test_constructor_default_values(): + """Test that constructor sets default values correctly.""" + freeze_tx = FreezeTransaction() + + assert freeze_tx.start_time is None + assert freeze_tx.file_id is None + assert freeze_tx.file_hash is None + assert freeze_tx.freeze_type is None + + +def test_build_transaction_body_with_valid_parameters(mock_account_ids, freeze_params): + """Test building a freeze transaction body with valid parameters.""" + operator_id, _, node_account_id, _, _ = mock_account_ids + + freeze_tx = FreezeTransaction( + start_time=freeze_params["start_time"], + file_id=freeze_params["file_id"], + file_hash=freeze_params["file_hash"], + freeze_type=freeze_params["freeze_type"], + ) + + # Set operator and node account IDs needed for building transaction body + freeze_tx.operator_account_id = operator_id + freeze_tx.node_account_id = node_account_id + + transaction_body = freeze_tx.build_transaction_body() + + # Verify the transaction body contains freeze field + assert transaction_body.HasField("freeze") + + # Verify all fields are correctly set + freeze_body = transaction_body.freeze + assert freeze_body.start_time == freeze_params["start_time"]._to_protobuf() + assert freeze_body.update_file == freeze_params["file_id"]._to_proto() + assert freeze_body.file_hash == freeze_params["file_hash"] + assert freeze_body.freeze_type == freeze_params["freeze_type"]._to_proto() + + +def test_build_transaction_body_with_none_values(mock_account_ids): + """Test building a freeze transaction body with None values.""" + operator_id, _, node_account_id, _, _ = mock_account_ids + + freeze_tx = FreezeTransaction() + + # Set operator and node account IDs needed for building transaction body + freeze_tx.operator_account_id = operator_id + freeze_tx.node_account_id = node_account_id + + transaction_body = freeze_tx.build_transaction_body() + + # Verify the transaction body contains freeze field + assert transaction_body.HasField("freeze") + + # Verify all fields are None or default values + freeze_body = transaction_body.freeze + assert not freeze_body.HasField("start_time") # Empty protobuf object when None + assert not freeze_body.HasField("update_file") # Empty protobuf object when None + assert freeze_body.file_hash == b"" # Empty bytes when None + assert freeze_body.freeze_type == proto_FreezeType.UNKNOWN_FREEZE_TYPE + + +def test_build_scheduled_body(freeze_params): + """Test building a schedulable freeze transaction body.""" + freeze_tx = FreezeTransaction( + start_time=freeze_params["start_time"], + file_id=freeze_params["file_id"], + file_hash=freeze_params["file_hash"], + freeze_type=freeze_params["freeze_type"], + ) + + schedulable_body = freeze_tx.build_scheduled_body() + + # Verify the correct type is returned + assert isinstance(schedulable_body, SchedulableTransactionBody) + + # Verify the transaction was built with freeze type + assert schedulable_body.HasField("freeze") + + # Verify fields in the schedulable body + freeze_body = schedulable_body.freeze + assert freeze_body.start_time == freeze_params["start_time"]._to_protobuf() + assert freeze_body.update_file == freeze_params["file_id"]._to_proto() + assert freeze_body.file_hash == freeze_params["file_hash"] + assert freeze_body.freeze_type == freeze_params["freeze_type"]._to_proto() + + +def test_set_start_time(freeze_params): + """Test setting start_time using the setter method.""" + freeze_tx = FreezeTransaction() + + result = freeze_tx.set_start_time(freeze_params["start_time"]) + + assert freeze_tx.start_time == freeze_params["start_time"] + assert result is freeze_tx # Should return self for method chaining + + +def test_set_file_id(freeze_params): + """Test setting file_id using the setter method.""" + freeze_tx = FreezeTransaction() + + result = freeze_tx.set_file_id(freeze_params["file_id"]) + + assert freeze_tx.file_id == freeze_params["file_id"] + assert result is freeze_tx # Should return self for method chaining + + +def test_set_file_hash(freeze_params): + """Test setting file_hash using the setter method.""" + freeze_tx = FreezeTransaction() + + result = freeze_tx.set_file_hash(freeze_params["file_hash"]) + + assert freeze_tx.file_hash == freeze_params["file_hash"] + assert result is freeze_tx # Should return self for method chaining + + +def test_set_freeze_type(freeze_params): + """Test setting freeze_type using the setter method.""" + freeze_tx = FreezeTransaction() + + result = freeze_tx.set_freeze_type(freeze_params["freeze_type"]) + + assert freeze_tx.freeze_type == freeze_params["freeze_type"] + assert result is freeze_tx # Should return self for method chaining + + +def test_method_chaining_with_all_setters(freeze_params): + """Test that all setter methods support method chaining.""" + freeze_tx = FreezeTransaction() + + result = ( + freeze_tx.set_start_time(freeze_params["start_time"]) + .set_file_id(freeze_params["file_id"]) + .set_file_hash(freeze_params["file_hash"]) + .set_freeze_type(freeze_params["freeze_type"]) + ) + + assert result is freeze_tx + assert freeze_tx.start_time == freeze_params["start_time"] + assert freeze_tx.file_id == freeze_params["file_id"] + assert freeze_tx.file_hash == freeze_params["file_hash"] + assert freeze_tx.freeze_type == freeze_params["freeze_type"] + + +def test_set_methods_require_not_frozen(mock_client, freeze_params): + """Test that setter methods raise exception when transaction is frozen.""" + freeze_tx = FreezeTransaction() + freeze_tx.freeze_with(mock_client) + + test_cases = [ + ("set_start_time", freeze_params["start_time"]), + ("set_file_id", freeze_params["file_id"]), + ("set_file_hash", freeze_params["file_hash"]), + ("set_freeze_type", freeze_params["freeze_type"]), + ] + + for method_name, value in test_cases: + with pytest.raises( + Exception, match="Transaction is immutable; it has been frozen" + ): + getattr(freeze_tx, method_name)(value) + + +def test_get_method(): + """Test retrieving the gRPC method for the transaction.""" + freeze_tx = FreezeTransaction() + + mock_channel = MagicMock() + mock_freeze_stub = MagicMock() + mock_channel.freeze = mock_freeze_stub + + method = freeze_tx._get_method(mock_channel) + + assert method.query is None + assert method.transaction == mock_freeze_stub.freeze + + +def test_sign_transaction(mock_client): + """Test signing the freeze transaction with a private key.""" + freeze_tx = FreezeTransaction() + freeze_tx.set_freeze_type(FreezeType.FREEZE_ONLY) + + private_key = MagicMock() + private_key.sign.return_value = b"signature" + private_key.public_key().to_bytes_raw.return_value = b"public_key" + + freeze_tx.freeze_with(mock_client) + freeze_tx.sign(private_key) + + node_id = mock_client.network.current_node._account_id + body_bytes = freeze_tx._transaction_body_bytes[node_id] + + assert len(freeze_tx._signature_map[body_bytes].sigPair) == 1 + sig_pair = freeze_tx._signature_map[body_bytes].sigPair[0] + assert sig_pair.pubKeyPrefix == b"public_key" + assert sig_pair.ed25519 == b"signature" + + +def test_to_proto(mock_client): + """Test converting the freeze transaction to protobuf format after signing.""" + freeze_tx = FreezeTransaction() + freeze_tx.set_freeze_type(FreezeType.FREEZE_ONLY) + + private_key = MagicMock() + private_key.sign.return_value = b"signature" + private_key.public_key().to_bytes_raw.return_value = b"public_key" + + freeze_tx.freeze_with(mock_client) + freeze_tx.sign(private_key) + proto = freeze_tx._to_proto() + + assert proto.signedTransactionBytes + assert len(proto.signedTransactionBytes) > 0 + + +def test_build_proto_body_with_all_fields(freeze_params): + """Test building protobuf body with all fields set.""" + freeze_tx = FreezeTransaction( + start_time=freeze_params["start_time"], + file_id=freeze_params["file_id"], + file_hash=freeze_params["file_hash"], + freeze_type=freeze_params["freeze_type"], + ) + + proto_body = freeze_tx._build_proto_body() + + assert proto_body.start_time == freeze_params["start_time"]._to_protobuf() + assert proto_body.update_file == freeze_params["file_id"]._to_proto() + assert proto_body.file_hash == freeze_params["file_hash"] + assert proto_body.freeze_type == freeze_params["freeze_type"]._to_proto() + + +def test_build_proto_body_with_none_fields(): + """Test building protobuf body with None fields.""" + freeze_tx = FreezeTransaction() + + proto_body = freeze_tx._build_proto_body() + + assert not proto_body.HasField("start_time") + assert not proto_body.HasField("update_file") + assert proto_body.file_hash == b"" + assert proto_body.freeze_type == proto_FreezeType.UNKNOWN_FREEZE_TYPE From 190fd1e3aff5456f36e9c926345892561101c8de Mon Sep 17 00:00:00 2001 From: dosi Date: Sun, 2 Nov 2025 17:35:14 +0200 Subject: [PATCH 5/7] chore: update changelog Signed-off-by: dosi --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8529f3d0..dddfaec41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. ## [Unreleased] ### Added +- added FreezeTransaction class +- added FreezeType class - Added `docs/sdk_developers/pylance.md`, a new guide explaining how to set up and use **Pylance** in VS Code for validating imports, file references, and methods before review. (#713) - docs: Add Google-style docstrings to `TokenId` class and its methods in `token_id.py`. - added Google-style docstrings to the `TransactionRecord` class including all dataclass fields, `__repr__`, `_from_proto()` & `_to_proto()` methods. From fd318a42104a6fc4954ae157a9b17db10485642f Mon Sep 17 00:00:00 2001 From: dosi Date: Sun, 2 Nov 2025 17:38:07 +0200 Subject: [PATCH 6/7] chore: add new classes to __init__.py Signed-off-by: dosi --- src/hiero_sdk_python/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/hiero_sdk_python/__init__.py b/src/hiero_sdk_python/__init__.py index b908328ea..4ebfffd6a 100644 --- a/src/hiero_sdk_python/__init__.py +++ b/src/hiero_sdk_python/__init__.py @@ -140,6 +140,10 @@ from .tokens.custom_royalty_fee import CustomRoyaltyFee from .transaction.custom_fee_limit import CustomFeeLimit +# System +from .system.freeze_transaction import FreezeTransaction +from .system.freeze_type import FreezeType + __all__ = [ # Client "Client", @@ -278,4 +282,8 @@ "CustomFractionalFee", "CustomRoyaltyFee", "CustomFeeLimit", + + # System + "FreezeTransaction", + "FreezeType", ] From 140dbb085bcea1786813d7c82ed492816961ccc9 Mon Sep 17 00:00:00 2001 From: dosi Date: Wed, 5 Nov 2025 22:55:00 +0200 Subject: [PATCH 7/7] chore: address PR feedback Signed-off-by: dosi --- src/hiero_sdk_python/system/freeze_transaction.py | 3 ++- src/hiero_sdk_python/system/freeze_type.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hiero_sdk_python/system/freeze_transaction.py b/src/hiero_sdk_python/system/freeze_transaction.py index 53f4a5a0b..bad258254 100644 --- a/src/hiero_sdk_python/system/freeze_transaction.py +++ b/src/hiero_sdk_python/system/freeze_transaction.py @@ -11,6 +11,7 @@ from hiero_sdk_python.hapi.services.schedulable_transaction_body_pb2 import ( SchedulableTransactionBody, ) +from hiero_sdk_python.hapi.services.transaction_pb2 import TransactionBody from hiero_sdk_python.system.freeze_type import FreezeType from hiero_sdk_python.timestamp import Timestamp from hiero_sdk_python.transaction.transaction import Transaction @@ -119,7 +120,7 @@ def _build_proto_body(self) -> FreezeTransactionBody: freeze_type=self.freeze_type._to_proto() if self.freeze_type else None, ) - def build_transaction_body(self): + def build_transaction_body(self) -> TransactionBody: """ Builds the transaction body for this freeze transaction. diff --git a/src/hiero_sdk_python/system/freeze_type.py b/src/hiero_sdk_python/system/freeze_type.py index 2b39a67d5..b9a3120d6 100644 --- a/src/hiero_sdk_python/system/freeze_type.py +++ b/src/hiero_sdk_python/system/freeze_type.py @@ -28,7 +28,7 @@ class FreezeType(Enum): TELEMETRY_UPGRADE = 5 @staticmethod - def _from_proto(proto_obj: proto_FreezeType): + def _from_proto(proto_obj: proto_FreezeType) -> "FreezeType": """ Converts a protobuf FreezeType to a FreezeType enum. @@ -72,8 +72,9 @@ def _to_proto(self) -> proto_FreezeType: return proto_FreezeType.TELEMETRY_UPGRADE return proto_FreezeType.UNKNOWN_FREEZE_TYPE - def __eq__(self, other): + def __eq__(self, other: object) -> bool: if isinstance(other, FreezeType): return self.value == other.value elif isinstance(other, int): return self.value == other + return False