Skip to content

Commit 8578522

Browse files
committed
fix(tokens): align TokenGrantKyc/RevokeKyc validation with TCK spec
Signed-off-by: iron-prog <dt915725@gmail.com>
1 parent c65aee7 commit 8578522

6 files changed

Lines changed: 68 additions & 297 deletions

File tree

src/hiero_sdk_python/tokens/token_grant_kyc_transaction.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,25 @@ def _build_proto_body(self) -> token_grant_kyc_pb2.TokenGrantKycTransactionBody:
7474
"""
7575
Returns the protobuf body for the token grant KYC transaction.
7676
77+
A missing token_id/account_id is intentionally NOT validated here.
78+
Per the TCK spec (see hiero-sdk-tck test-token-grant-kyc-transaction.ts,
79+
"Token ID" #4 and "Account ID" #3), a request with a missing tokenId or
80+
accountId must reach the network and receive a real precheck/receipt
81+
rejection (INVALID_TOKEN_ID / INVALID_ACCOUNT_ID), not a local
82+
validation error. An explicitly empty string ("") still fails earlier,
83+
in TokenId.from_string()/AccountId.from_string(), which matches the
84+
TCK spec's expectation of a local/internal error for that case.
85+
7786
Returns:
7887
TokenGrantKycTransactionBody: The protobuf body for this transaction.
79-
80-
Raises:
81-
ValueError: If the token ID or account ID is not set.
8288
"""
83-
if self.token_id is None:
84-
raise ValueError("Missing token ID")
85-
86-
if self.account_id is None:
87-
raise ValueError("Missing account ID")
89+
kwargs = {}
90+
if self.token_id is not None:
91+
kwargs["token"] = self.token_id._to_proto()
92+
if self.account_id is not None:
93+
kwargs["account"] = self.account_id._to_proto()
8894

89-
return TokenGrantKycTransactionBody(token=self.token_id._to_proto(), account=self.account_id._to_proto())
95+
return TokenGrantKycTransactionBody(**kwargs)
9096

9197
def build_transaction_body(self) -> transaction_pb2.TransactionBody:
9298
"""

src/hiero_sdk_python/tokens/token_revoke_kyc_transaction.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,21 @@ def set_account_id(self, account_id: AccountId) -> TokenRevokeKycTransaction:
7373

7474
def _build_proto_body(self) -> token_revoke_kyc_pb2.TokenRevokeKycTransactionBody:
7575
"""
76-
Returns the protobuf body for the token revoke KYC transaction.
76+
Builds the protobuf body for this token revoke KYC transaction.
7777
78-
Returns:
79-
TokenRevokeKycTransactionBody: The protobuf body for this transaction.
78+
Missing token_id/account_id are intentionally omitted so validation is
79+
performed by the network, in accordance with the TCK specification.
8080
81-
Raises:
82-
ValueError: If the token ID or account ID is not set.
81+
Returns:
82+
TokenRevokeKycTransactionBody: The built protobuf body.
8383
"""
84-
if self.token_id is None:
85-
raise ValueError("Missing token ID")
86-
87-
if self.account_id is None:
88-
raise ValueError("Missing account ID")
84+
kwargs = {}
85+
if self.token_id is not None:
86+
kwargs["token"] = self.token_id._to_proto()
87+
if self.account_id is not None:
88+
kwargs["account"] = self.account_id._to_proto()
8989

90-
return TokenRevokeKycTransactionBody(token=self.token_id._to_proto(), account=self.account_id._to_proto())
90+
return TokenRevokeKycTransactionBody(**kwargs)
9191

9292
def build_transaction_body(self) -> transaction_pb2.AtomicBatchTransactionBody:
9393
"""

tck/handlers/token.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from typing import Protocol
6+
57
from hiero_sdk_python.account.account_id import AccountId
68
from hiero_sdk_python.Duration import Duration
79
from hiero_sdk_python.response_code import ResponseCode
@@ -26,6 +28,7 @@
2628
from hiero_sdk_python.tokens.token_pause_transaction import TokenPauseTransaction
2729
from hiero_sdk_python.tokens.token_revoke_kyc_transaction import TokenRevokeKycTransaction
2830
from hiero_sdk_python.tokens.token_type import TokenType
31+
from hiero_sdk_python.transaction.transaction import Transaction
2932
from hiero_sdk_python.transaction.transaction_receipt import TransactionReceipt
3033
from tck.handlers.registry import rpc_method
3134
from tck.param.custom_fee import CustomFeeParams, FixedFeeParams
@@ -290,16 +293,30 @@ def _build_delete_token_transaction(params: DeleteTokenParams) -> TokenDeleteTra
290293
return transaction
291294

292295

293-
def _build_freeze_token_transaction(params: FreezeTokenParams) -> TokenFreezeTransaction:
294-
"""Build a TokenFreezeTransaction from TCK params."""
295-
transaction = TokenFreezeTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
296+
class _HasTokenAndAccountId(Protocol):
297+
"""Structural type for TCK params that carry an optional tokenId/accountId.
298+
299+
Matches FreezeTokenParams, GrantTokenKycParams, RevokeTokenKycParams, and
300+
any future status-only endpoint (e.g. unfreezeToken) with this same shape.
301+
"""
302+
303+
tokenId: str | None
304+
accountId: str | None
305+
296306

307+
def _apply_token_account_ids(transaction: Transaction, params: _HasTokenAndAccountId) -> None:
308+
"""Apply tokenId/accountId from TCK params onto a transaction, if present."""
297309
if params.tokenId is not None:
298310
transaction.set_token_id(TokenId.from_string(params.tokenId))
299311

300312
if params.accountId is not None:
301313
transaction.set_account_id(AccountId.from_string(params.accountId))
302314

315+
316+
def _build_freeze_token_transaction(params: FreezeTokenParams) -> TokenFreezeTransaction:
317+
"""Build a TokenFreezeTransaction from TCK params."""
318+
transaction = TokenFreezeTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
319+
_apply_token_account_ids(transaction, params)
303320
return transaction
304321

305322

@@ -316,26 +333,14 @@ def _build_pause_token_transaction(params: PauseTokenParams) -> TokenPauseTransa
316333
def _build_grant_token_kyc_transaction(params: GrantTokenKycParams) -> TokenGrantKycTransaction:
317334
"""Build a TokenGrantKycTransaction from TCK params."""
318335
transaction = TokenGrantKycTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
319-
320-
if params.tokenId is not None:
321-
transaction.set_token_id(TokenId.from_string(params.tokenId))
322-
323-
if params.accountId is not None:
324-
transaction.set_account_id(AccountId.from_string(params.accountId))
325-
336+
_apply_token_account_ids(transaction, params)
326337
return transaction
327338

328339

329340
def _build_revoke_token_kyc_transaction(params: RevokeTokenKycParams) -> TokenRevokeKycTransaction:
330341
"""Build a TokenRevokeKycTransaction from TCK params."""
331342
transaction = TokenRevokeKycTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
332-
333-
if params.tokenId is not None:
334-
transaction.set_token_id(TokenId.from_string(params.tokenId))
335-
336-
if params.accountId is not None:
337-
transaction.set_account_id(AccountId.from_string(params.accountId))
338-
343+
_apply_token_account_ids(transaction, params)
339344
return transaction
340345

341346

tests/tck/token_kyc_handlers_test.py

Lines changed: 0 additions & 240 deletions
This file was deleted.

0 commit comments

Comments
 (0)