Skip to content

Commit 309c38d

Browse files
authored
feat (tck): add updateAccount endpoint with request and response models (hiero-ledger#2320)
Signed-off-by: Ntege Daniel <danientege785@gmail.com>
1 parent 705757b commit 309c38d

5 files changed

Lines changed: 107 additions & 11 deletions

File tree

src/hiero_sdk_python/account/account_update_transaction.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,9 @@ def _build_proto_body(self):
284284
285285
Returns:
286286
CryptoUpdateTransactionBody: The protobuf body for this transaction.
287-
288-
Raises:
289-
ValueError: If account_id is not set.
290287
"""
291-
if self.account_id is None:
292-
raise ValueError("Missing required AccountID to update")
293-
294288
proto_body = CryptoUpdateTransactionBody(
295-
accountIDToUpdate=self.account_id._to_proto(),
289+
accountIDToUpdate=self.account_id._to_proto() if self.account_id else None,
296290
key=self.key.to_proto_key() if self.key else None,
297291
memo=StringValue(value=self.account_memo) if self.account_memo is not None else None,
298292
autoRenewPeriod=(self.auto_renew_period._to_proto() if self.auto_renew_period else None),

tck/handlers/account.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@
55
from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
66
from hiero_sdk_python.account.account_id import AccountId
77
from hiero_sdk_python.account.account_info import AccountInfo
8+
from hiero_sdk_python.account.account_update_transaction import AccountUpdateTransaction
9+
from hiero_sdk_python.Duration import Duration
810
from hiero_sdk_python.hbar import Hbar
911
from hiero_sdk_python.query.account_info_query import AccountInfoQuery
1012
from hiero_sdk_python.response_code import ResponseCode
13+
from hiero_sdk_python.timestamp import Timestamp
1114
from hiero_sdk_python.transaction.transaction_receipt import TransactionReceipt
1215
from tck.handlers.registry import rpc_method
13-
from tck.param.account import CreateAccountParams, GetAccountInfoParams
16+
from tck.param.account import CreateAccountParams, GetAccountInfoParams, UpdateAccountParams
1417
from tck.response.account import (
1518
CreateAccountResponse,
1619
GetAccountInfoResponse,
1720
StakingInfoResponse,
1821
TokenRelationshipResponse,
22+
UpdateAccountResponse,
1923
)
2024
from tck.util.client_utils import get_client
2125
from tck.util.constants import DEFAULT_GRPC_TIMEOUT
@@ -78,6 +82,59 @@ def create_account(params: CreateAccountParams) -> CreateAccountResponse:
7882
return CreateAccountResponse(account_id, ResponseCode(receipt.status).name)
7983

8084

85+
def _build_update_account_transaction(params: UpdateAccountParams) -> AccountUpdateTransaction:
86+
transaction = AccountUpdateTransaction().set_grpc_deadline(DEFAULT_GRPC_TIMEOUT)
87+
transaction.set_auto_renew_period(None)
88+
89+
if params.accountId is not None:
90+
transaction.set_account_id(AccountId.from_string(params.accountId))
91+
92+
if params.key is not None:
93+
transaction.set_key(get_key_from_string(params.key))
94+
95+
if params.expirationTime is not None:
96+
transaction.set_expiration_time(Timestamp(params.expirationTime, 0))
97+
98+
if params.receiverSignatureRequired is not None:
99+
transaction.set_receiver_signature_required(params.receiverSignatureRequired)
100+
101+
if params.maxAutoTokenAssociations is not None:
102+
transaction.set_max_automatic_token_associations(params.maxAutoTokenAssociations)
103+
104+
if params.stakedAccountId is not None:
105+
transaction.set_staked_account_id(AccountId.from_string(params.stakedAccountId))
106+
107+
if params.stakedNodeId is not None:
108+
transaction.set_staked_node_id(params.stakedNodeId)
109+
110+
if params.declineStakingReward is not None:
111+
transaction.set_decline_staking_reward(params.declineStakingReward)
112+
113+
if params.memo is not None:
114+
transaction.set_account_memo(params.memo)
115+
116+
if params.autoRenewPeriod is not None:
117+
transaction.set_auto_renew_period(Duration(params.autoRenewPeriod))
118+
119+
return transaction
120+
121+
122+
@rpc_method("updateAccount")
123+
def update_account(params: UpdateAccountParams) -> UpdateAccountResponse:
124+
"""Update an account using TCK updateAccount parameters."""
125+
client = get_client(params.sessionId)
126+
127+
transaction = _build_update_account_transaction(params)
128+
129+
if params.commonTransactionParams is not None:
130+
params.commonTransactionParams.apply_common_params(transaction, client)
131+
132+
response = transaction.execute(client, wait_for_receipt=False)
133+
receipt: TransactionReceipt = response.get_receipt(client, validate_status=True)
134+
135+
return UpdateAccountResponse(ResponseCode(receipt.status).name)
136+
137+
81138
def _enum_name(value) -> str | None:
82139
if value is None:
83140
return None

tck/param/account.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,44 @@ def parse_json_params(cls, params: dict) -> CreateAccountParams:
4747
)
4848

4949

50+
@dataclass
51+
class UpdateAccountParams(BaseTransactionParams):
52+
"""Request parameters for the updateAccount endpoint."""
53+
54+
accountId: str | None = None
55+
key: str | None = None
56+
receiverSignatureRequired: bool | None = None
57+
autoRenewPeriod: int | None = None
58+
expirationTime: int | None = None
59+
memo: str | None = None
60+
maxAutoTokenAssociations: int | None = None
61+
stakedAccountId: str | None = None
62+
stakedNodeId: int | None = None
63+
declineStakingReward: bool | None = None
64+
65+
@classmethod
66+
def parse_json_params(cls, params: dict) -> UpdateAccountParams:
67+
"""Parse JSON-RPC params into an UpdateAccountParams instance."""
68+
decline_staking_reward = params.get("declineStakingReward")
69+
if decline_staking_reward is None:
70+
decline_staking_reward = params.get("declineStakingRewards")
71+
72+
return cls(
73+
accountId=params.get("accountId"),
74+
key=params.get("key"),
75+
receiverSignatureRequired=to_bool(params.get("receiverSignatureRequired")),
76+
autoRenewPeriod=to_int(params.get("autoRenewPeriod")),
77+
expirationTime=to_int(params.get("expirationTime")),
78+
memo=params.get("memo"),
79+
maxAutoTokenAssociations=to_int(params.get("maxAutoTokenAssociations")),
80+
stakedAccountId=params.get("stakedAccountId"),
81+
stakedNodeId=to_int(params.get("stakedNodeId")),
82+
declineStakingReward=to_bool(decline_staking_reward),
83+
sessionId=parse_session_id(params),
84+
commonTransactionParams=parse_common_transaction_params(params),
85+
)
86+
87+
5088
@dataclass
5189
class GetAccountInfoParams(BaseParams):
5290
"""Request parameters for the getAccountInfo endpoint."""

tck/response/account.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ class CreateAccountResponse:
1313
status: str | None = None
1414

1515

16+
@dataclass
17+
class UpdateAccountResponse:
18+
"""Response payload for updateAccount."""
19+
20+
status: str | None = None
21+
22+
1623
@dataclass
1724
class StakingInfoResponse:
1825
"""Nested staking fields in the getAccountInfo response."""

tests/unit/account_update_transaction_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,11 @@ def test_build_transaction_body_receiver_sig_required_variants(mock_account_ids)
332332

333333

334334
def test_missing_account_id():
335-
"""Test that building a transaction without setting account_id raises a ValueError."""
335+
"""Test that building a transaction without setting account_id omits the field from proto."""
336336
account_tx = AccountUpdateTransaction()
337337

338-
with pytest.raises(ValueError, match="Missing required AccountID to update"):
339-
account_tx.build_transaction_body()
338+
proto_body = account_tx._build_proto_body()
339+
assert not proto_body.HasField("accountIDToUpdate")
340340

341341

342342
def test_sign_transaction(mock_client):

0 commit comments

Comments
 (0)