Skip to content

Commit 2a3959d

Browse files
authored
feat: Add UnfreezeToken To TCK (#2529)
Signed-off-by: aceppaluni <aceppaluni@gmail.com>
1 parent 075f0d3 commit 2a3959d

5 files changed

Lines changed: 77 additions & 20 deletions

File tree

src/hiero_sdk_python/tokens/token_unfreeze_transaction.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,16 @@ def _build_proto_body(self) -> token_unfreeze_account_pb2.TokenUnfreezeAccountTr
7676
7777
Returns:
7878
TokenUnfreezeAccountTransactionBody: The protobuf body for this transaction.
79-
80-
Raises:
81-
ValueError: If account ID or token ID is not set.
8279
"""
83-
if not self.token_id:
84-
raise ValueError("Missing required TokenID.")
80+
body = token_unfreeze_account_pb2.TokenUnfreezeAccountTransactionBody()
81+
82+
if self.token_id is not None:
83+
body.token.CopyFrom(self.token_id._to_proto())
8584

86-
if not self.account_id:
87-
raise ValueError("Missing required AccountID.")
85+
if self.account_id is not None:
86+
body.account.CopyFrom(self.account_id._to_proto())
8887

89-
return token_unfreeze_account_pb2.TokenUnfreezeAccountTransactionBody(
90-
account=self.account_id._to_proto(), token=self.token_id._to_proto()
91-
)
88+
return body
9289

9390
def build_transaction_body(self) -> transaction_pb2.TransactionBody:
9491
"""

tck/handlers/token.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from hiero_sdk_python.tokens.token_reject_transaction import TokenRejectTransaction
3636
from hiero_sdk_python.tokens.token_revoke_kyc_transaction import TokenRevokeKycTransaction
3737
from hiero_sdk_python.tokens.token_type import TokenType
38+
from hiero_sdk_python.tokens.token_unfreeze_transaction import TokenUnfreezeTransaction
3839
from hiero_sdk_python.tokens.token_update_transaction import TokenUpdateTransaction
3940
from hiero_sdk_python.tokens.token_wipe_transaction import TokenWipeTransaction
4041
from hiero_sdk_python.transaction.transaction_receipt import TransactionReceipt
@@ -55,6 +56,7 @@
5556
PauseTokenParams,
5657
RejectTokenParams,
5758
RevokeTokenKycParams,
59+
UnfreezeTokenParams,
5860
UpdateTokenParams,
5961
WipeTokenParams,
6062
)
@@ -74,6 +76,7 @@
7476
PauseTokenResponse,
7577
RejectTokenResponse,
7678
RevokeTokenKycResponse,
79+
UnfreezeTokenResponse,
7780
UpdateTokenResponse,
7881
WipeTokenResponse,
7982
)
@@ -419,6 +422,37 @@ def dissociate_token(params: DissociateTokenParams) -> DissociateTokenResponse:
419422
return DissociateTokenResponse(status=ResponseCode(receipt.status).name)
420423

421424

425+
def _build_unfreeze_token_transaction(
426+
params: UnfreezeTokenParams,
427+
) -> TokenUnfreezeTransaction:
428+
"""Build a TokenUnfreezeTransaction from TCK params."""
429+
transaction = TokenUnfreezeTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
430+
431+
if params.tokenId is not None:
432+
transaction.set_token_id(TokenId.from_string(params.tokenId))
433+
434+
if params.accountId is not None:
435+
transaction.set_account_id(AccountId.from_string(params.accountId))
436+
437+
return transaction
438+
439+
440+
@rpc_method("unfreezeToken")
441+
def unfreeze_token(params: UnfreezeTokenParams) -> UnfreezeTokenResponse:
442+
"""Unfreeze a token for an account using TCK unfreezeToken parameters."""
443+
client = get_client(params.sessionId)
444+
445+
transaction = _build_unfreeze_token_transaction(params)
446+
447+
if params.commonTransactionParams is not None:
448+
params.commonTransactionParams.apply_common_params(transaction, client)
449+
450+
response = transaction.execute(client, wait_for_receipt=False)
451+
receipt: TransactionReceipt = response.get_receipt(client, validate_status=True)
452+
453+
return UnfreezeTokenResponse(status=ResponseCode(receipt.status).name)
454+
455+
422456
@rpc_method("freezeToken")
423457
def freeze_token(params: FreezeTokenParams) -> FreezeTokenResponse:
424458
"""Freeze a token for an account using TCK freezeToken parameters."""

tck/param/token.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,23 @@ def parse_json_params(cls, params: dict) -> FreezeTokenParams:
166166
)
167167

168168

169+
@dataclass
170+
class UnfreezeTokenParams(BaseTransactionParams):
171+
"""Request parameters for the unfreezeToken endpoint."""
172+
173+
tokenId: str | None = None
174+
accountId: str | None = None
175+
176+
@classmethod
177+
def parse_json_params(cls, params: dict) -> UnfreezeTokenParams:
178+
return cls(
179+
tokenId=params.get("tokenId"),
180+
accountId=params.get("accountId"),
181+
sessionId=parse_session_id(params),
182+
commonTransactionParams=parse_common_transaction_params(params),
183+
)
184+
185+
169186
@dataclass
170187
class DissociateTokenParams(BaseTransactionParams):
171188
"""Request parameters for the dissociateToken endpoint."""

tck/response/token.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ class FreezeTokenResponse(StatusOnlyResponse):
4444
"""Response payload for freezeToken."""
4545

4646

47+
@dataclass
48+
class UnfreezeTokenResponse(StatusOnlyResponse):
49+
"""Response payload for unfreezeToken."""
50+
51+
4752
@dataclass
4853
class GrantTokenKycResponse(StatusOnlyResponse):
4954
"""Response payload for grantTokenKyc."""

tests/unit/token_unfreeze_transaction_test.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,25 +47,29 @@ def test_build_transaction_body(mock_account_ids):
4747

4848

4949
def test_missing_token_id(mock_account_ids):
50-
"""Test that building a transaction without setting
51-
TokenID raises a ValueError.
52-
"""
53-
account_id, freeze_id, node_account_id, token_id, _ = mock_account_ids
50+
"""Test that building the protobuf body without TokenID ignores the missing ID."""
51+
_, freeze_id, _, _, _ = mock_account_ids
5452

5553
unfreeze_tx = TokenUnfreezeTransaction()
5654
unfreeze_tx.set_account_id(freeze_id)
57-
with pytest.raises(ValueError, match="Missing required TokenID."):
58-
unfreeze_tx.build_transaction_body()
55+
56+
body = unfreeze_tx._build_proto_body()
57+
58+
assert not body.HasField("token")
59+
assert body.account == freeze_id._to_proto()
5960

6061

6162
def test_missing_account_id(mock_account_ids):
62-
"""Test that building a transaction without setting AccountID raises a ValueError."""
63-
account_id, freeze_id, node_account_id, token_id, _ = mock_account_ids
63+
"""Test that building the protobuf body without AccountID ignores the missing ID."""
64+
_, _, _, token_id, _ = mock_account_ids
6465

6566
unfreeze_tx = TokenUnfreezeTransaction()
6667
unfreeze_tx.set_token_id(token_id)
67-
with pytest.raises(ValueError, match="Missing required AccountID."):
68-
unfreeze_tx.build_transaction_body()
68+
69+
body = unfreeze_tx._build_proto_body()
70+
71+
assert not body.HasField("account")
72+
assert body.token == token_id._to_proto()
6973

7074

7175
def test_sign_transaction(mock_account_ids, mock_client):

0 commit comments

Comments
 (0)