Skip to content

Commit bf5d07d

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

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.hbar import Hbar
@@ -32,6 +34,7 @@
3234
from hiero_sdk_python.tokens.token_pause_transaction import TokenPauseTransaction
3335
from hiero_sdk_python.tokens.token_revoke_kyc_transaction import TokenRevokeKycTransaction
3436
from hiero_sdk_python.tokens.token_type import TokenType
37+
from hiero_sdk_python.transaction.transaction import Transaction
3538
from hiero_sdk_python.transaction.transaction_receipt import TransactionReceipt
3639
from tck.handlers.registry import rpc_method
3740
from tck.param.custom_fee import CustomFeeParams, FixedFeeParams
@@ -299,16 +302,30 @@ def _build_delete_token_transaction(params: DeleteTokenParams) -> TokenDeleteTra
299302
return transaction
300303

301304

302-
def _build_freeze_token_transaction(params: FreezeTokenParams) -> TokenFreezeTransaction:
303-
"""Build a TokenFreezeTransaction from TCK params."""
304-
transaction = TokenFreezeTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
305+
class _HasTokenAndAccountId(Protocol):
306+
"""Structural type for TCK params that carry an optional tokenId/accountId.
307+
308+
Matches FreezeTokenParams, GrantTokenKycParams, RevokeTokenKycParams, and
309+
any future status-only endpoint (e.g. unfreezeToken) with this same shape.
310+
"""
311+
312+
tokenId: str | None
313+
accountId: str | None
314+
305315

316+
def _apply_token_account_ids(transaction: Transaction, params: _HasTokenAndAccountId) -> None:
317+
"""Apply tokenId/accountId from TCK params onto a transaction, if present."""
306318
if params.tokenId is not None:
307319
transaction.set_token_id(TokenId.from_string(params.tokenId))
308320

309321
if params.accountId is not None:
310322
transaction.set_account_id(AccountId.from_string(params.accountId))
311323

324+
325+
def _build_freeze_token_transaction(params: FreezeTokenParams) -> TokenFreezeTransaction:
326+
"""Build a TokenFreezeTransaction from TCK params."""
327+
transaction = TokenFreezeTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
328+
_apply_token_account_ids(transaction, params)
312329
return transaction
313330

314331

@@ -325,26 +342,14 @@ def _build_pause_token_transaction(params: PauseTokenParams) -> TokenPauseTransa
325342
def _build_grant_token_kyc_transaction(params: GrantTokenKycParams) -> TokenGrantKycTransaction:
326343
"""Build a TokenGrantKycTransaction from TCK params."""
327344
transaction = TokenGrantKycTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
328-
329-
if params.tokenId is not None:
330-
transaction.set_token_id(TokenId.from_string(params.tokenId))
331-
332-
if params.accountId is not None:
333-
transaction.set_account_id(AccountId.from_string(params.accountId))
334-
345+
_apply_token_account_ids(transaction, params)
335346
return transaction
336347

337348

338349
def _build_revoke_token_kyc_transaction(params: RevokeTokenKycParams) -> TokenRevokeKycTransaction:
339350
"""Build a TokenRevokeKycTransaction from TCK params."""
340351
transaction = TokenRevokeKycTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
341-
342-
if params.tokenId is not None:
343-
transaction.set_token_id(TokenId.from_string(params.tokenId))
344-
345-
if params.accountId is not None:
346-
transaction.set_account_id(AccountId.from_string(params.accountId))
347-
352+
_apply_token_account_ids(transaction, params)
348353
return transaction
349354

350355

tests/tck/token_kyc_handlers_test.py

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

0 commit comments

Comments
 (0)