99from hiero_sdk_python .contract .contract_info import ContractInfo
1010from hiero_sdk_python .crypto .private_key import PrivateKey
1111from hiero_sdk_python .Duration import Duration
12+ from hiero_sdk_python .hapi .services .basic_types_pb2 import StakingInfo as StakingInfoProto
1213from hiero_sdk_python .hapi .services .contract_get_info_pb2 import ContractGetInfoResponse
14+ from hiero_sdk_python .staking_info import StakingInfo
1315from hiero_sdk_python .timestamp import Timestamp
1416from hiero_sdk_python .tokens .token_freeze_status import TokenFreezeStatus
1517from hiero_sdk_python .tokens .token_id import TokenId
@@ -76,6 +78,10 @@ def contract_info(token_relationship):
7678 ledger_id = b"test_ledger_id" ,
7779 max_automatic_token_associations = 10 ,
7880 token_relationships = [token_relationship ],
81+ staking_info = StakingInfo (
82+ staked_account_id = AccountId (0 , 0 , 500 ),
83+ decline_reward = False ,
84+ ),
7985 )
8086
8187
@@ -99,6 +105,10 @@ def proto_contract_info(token_relationship):
99105 ledger_id = b"test_ledger_id" ,
100106 max_automatic_token_associations = 10 ,
101107 tokenRelationships = [token_relationship ._to_proto ()],
108+ staking_info = StakingInfoProto (
109+ staked_account_id = AccountId (0 , 0 , 500 )._to_proto (),
110+ decline_reward = False ,
111+ ),
102112 )
103113 return proto
104114
@@ -120,6 +130,9 @@ def test_contract_info_initialization(contract_info):
120130 assert contract_info .max_automatic_token_associations == 10
121131 assert len (contract_info .token_relationships ) == 1
122132 assert contract_info .token_relationships [0 ].token_id == TokenId (0 , 0 , 500 )
133+ assert contract_info .staking_info .staked_account_id == AccountId (0 , 0 , 500 )
134+ assert contract_info .staking_info .staked_node_id is None
135+ assert contract_info .staking_info .decline_reward is False
123136
124137
125138def test_contract_info_default_initialization ():
@@ -139,6 +152,7 @@ def test_contract_info_default_initialization():
139152 assert contract_info .ledger_id is None
140153 assert contract_info .max_automatic_token_associations is None
141154 assert not contract_info .token_relationships
155+ assert contract_info .staking_info is None
142156
143157
144158def test_from_proto (proto_contract_info ):
@@ -160,6 +174,10 @@ def test_from_proto(proto_contract_info):
160174 assert contract_info .max_automatic_token_associations == 10
161175 assert len (contract_info .token_relationships ) == 1
162176 assert contract_info .token_relationships [0 ].token_id == TokenId (0 , 0 , 500 )
177+ assert contract_info .staking_info is not None
178+ assert contract_info .staking_info .staked_account_id == AccountId (0 , 0 , 500 )
179+ assert contract_info .staking_info .staked_node_id is None
180+ assert contract_info .staking_info .decline_reward is False
163181
164182
165183def test_from_proto_with_empty_token_relationships ():
@@ -272,6 +290,9 @@ def test_proto_conversion_full_object(contract_info):
272290 == contract_info .max_automatic_token_associations
273291 )
274292 assert len (converted .token_relationships ) == len (contract_info .token_relationships )
293+ assert converted .staking_info .staked_account_id == contract_info .staking_info .staked_account_id
294+ assert converted .staking_info .staked_node_id == contract_info .staking_info .staked_node_id
295+ assert converted .staking_info .decline_reward == contract_info .staking_info .decline_reward
275296
276297
277298def test_proto_conversion_multiple_token_relationships (multiple_token_relationships ):
@@ -307,3 +328,164 @@ def test_proto_conversion_minimal_fields():
307328 assert converted .balance == contract_info .balance
308329 assert converted .admin_key is None
309330 assert not converted .token_relationships
331+
332+
333+ def test_from_proto_with_no_staking_info ():
334+ """Test from_proto with no staking info"""
335+ public_key = PrivateKey .generate_ed25519 ().public_key ()
336+ proto = ContractGetInfoResponse .ContractInfo (
337+ contractID = ContractId (0 , 0 , 200 )._to_proto (),
338+ accountID = AccountId (0 , 0 , 300 )._to_proto (),
339+ contractAccountID = "0.0.300" ,
340+ adminKey = public_key ._to_proto (),
341+ storage = 1024 ,
342+ balance = 5000000 ,
343+ )
344+
345+ contract_info = ContractInfo ._from_proto (proto )
346+
347+ assert contract_info .contract_id == ContractId (0 , 0 , 200 )
348+ assert contract_info .staking_info is None
349+
350+
351+ def test_from_proto_with_staked_node_id ():
352+ """Test from_proto with staked_node_id (staked to node)"""
353+ proto = ContractGetInfoResponse .ContractInfo (
354+ contractID = ContractId (0 , 0 , 200 )._to_proto (),
355+ accountID = AccountId (0 , 0 , 300 )._to_proto (),
356+ storage = 1024 ,
357+ balance = 5000000 ,
358+ staking_info = StakingInfoProto (
359+ staked_node_id = 3 ,
360+ decline_reward = True ,
361+ ),
362+ )
363+
364+ contract_info = ContractInfo ._from_proto (proto )
365+
366+ assert contract_info .staking_info is not None
367+ assert contract_info .staking_info .staked_account_id is None
368+ assert contract_info .staking_info .staked_node_id == 3
369+ assert contract_info .staking_info .decline_reward is True
370+
371+
372+ def test_to_proto_with_staked_account_id ():
373+ """Test to_proto with staked_account_id"""
374+ contract_info = ContractInfo (
375+ contract_id = ContractId (0 , 0 , 200 ),
376+ account_id = AccountId (0 , 0 , 300 ),
377+ balance = 5000000 ,
378+ staking_info = StakingInfo (
379+ staked_account_id = AccountId (0 , 0 , 500 ),
380+ decline_reward = False ,
381+ ),
382+ )
383+
384+ proto = contract_info ._to_proto ()
385+
386+ assert proto .HasField ('staking_info' )
387+ assert proto .staking_info .HasField ('staked_account_id' )
388+ assert proto .staking_info .staked_account_id == AccountId (0 , 0 , 500 )._to_proto ()
389+ assert proto .staking_info .decline_reward is False
390+
391+
392+ def test_to_proto_with_staked_node_id ():
393+ """Test to_proto with staked_node_id"""
394+ contract_info = ContractInfo (
395+ contract_id = ContractId (0 , 0 , 200 ),
396+ account_id = AccountId (0 , 0 , 300 ),
397+ balance = 5000000 ,
398+ staking_info = StakingInfo (
399+ staked_node_id = 5 ,
400+ decline_reward = True ,
401+ ),
402+ )
403+
404+ proto = contract_info ._to_proto ()
405+
406+ assert proto .HasField ('staking_info' )
407+ assert proto .staking_info .staked_node_id == 5
408+ assert proto .staking_info .decline_reward is True
409+
410+
411+ def test_proto_conversion_staking_node_round_trip ():
412+ """Test proto conversion round trip with staked_node_id"""
413+ contract_info = ContractInfo (
414+ contract_id = ContractId (0 , 0 , 200 ),
415+ account_id = AccountId (0 , 0 , 300 ),
416+ balance = 5000000 ,
417+ staking_info = StakingInfo (
418+ staked_node_id = 7 ,
419+ decline_reward = False ,
420+ ),
421+ )
422+
423+ converted = ContractInfo ._from_proto (contract_info ._to_proto ())
424+
425+ assert converted .contract_id == contract_info .contract_id
426+ assert converted .account_id == contract_info .account_id
427+ assert converted .balance == contract_info .balance
428+ assert converted .staking_info .staked_account_id is None
429+ assert converted .staking_info .staked_node_id == 7
430+ assert isinstance (converted .staking_info .staked_node_id , int )
431+ assert converted .staking_info .decline_reward is False
432+
433+
434+ def test_proto_conversion_staking_account_round_trip ():
435+ """Test proto conversion round trip with staked_account_id"""
436+ contract_info = ContractInfo (
437+ contract_id = ContractId (0 , 0 , 200 ),
438+ account_id = AccountId (0 , 0 , 300 ),
439+ balance = 5000000 ,
440+ staking_info = StakingInfo (
441+ staked_account_id = AccountId (0 , 0 , 600 ),
442+ decline_reward = True ,
443+ ),
444+ )
445+
446+ converted = ContractInfo ._from_proto (contract_info ._to_proto ())
447+
448+ assert converted .contract_id == contract_info .contract_id
449+ assert converted .account_id == contract_info .account_id
450+ assert converted .balance == contract_info .balance
451+ assert converted .staking_info .staked_account_id == AccountId (0 , 0 , 600 )
452+ assert isinstance (converted .staking_info .staked_account_id , AccountId )
453+ assert converted .staking_info .staked_node_id is None
454+ assert converted .staking_info .decline_reward is True
455+
456+
457+ def test_proto_conversion_with_staked_node_zero ():
458+ """Test proto conversion with staked_node_id set to 0 (valid edge case)"""
459+ contract_info = ContractInfo (
460+ contract_id = ContractId (0 , 0 , 200 ),
461+ account_id = AccountId (0 , 0 , 300 ),
462+ balance = 5000000 ,
463+ staking_info = StakingInfo (
464+ staked_node_id = 0 ,
465+ decline_reward = True ,
466+ ),
467+ )
468+
469+ converted = ContractInfo ._from_proto (contract_info ._to_proto ())
470+
471+ assert converted .staking_info is not None
472+ assert converted .staking_info .staked_node_id == 0
473+ assert isinstance (converted .staking_info .staked_node_id , int )
474+ assert converted .staking_info .decline_reward is True
475+
476+
477+ def test_proto_conversion_no_staking_info_round_trip ():
478+ """Test proto conversion round trip with no staking info (None should stay None)"""
479+ contract_info = ContractInfo (
480+ contract_id = ContractId (0 , 0 , 200 ),
481+ account_id = AccountId (0 , 0 , 300 ),
482+ balance = 5000000 ,
483+ staking_info = None ,
484+ )
485+
486+ converted = ContractInfo ._from_proto (contract_info ._to_proto ())
487+
488+ assert converted .contract_id == contract_info .contract_id
489+ assert converted .account_id == contract_info .account_id
490+ assert converted .balance == contract_info .balance
491+ assert converted .staking_info is None
0 commit comments