Skip to content

Commit b3f2aeb

Browse files
authored
Merge pull request #39 from exploreriii/TokenFreezeTransaction
TokenFreezeTransaction
2 parents 1e5551e + 44afba7 commit b3f2aeb

File tree

11 files changed

+351
-36
lines changed

11 files changed

+351
-36
lines changed

README.md

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This is a Python SDK for interacting with the Hedera Hashgraph platform. It allows developers to:
44

5-
- Manage Token Transactions like Create, Mint Fungible, Mint Non-Fungible, Associate, Dissociate, Transfer & Delete
5+
- Manage Token Transactions like Create, Mint Fungible, Mint Non-Fungible, Associate, Dissociate, Transfer, Freeze & Delete
66
- Manage Consensus Transactions like Topic Create, Update, Delete
77
- Submit Topic Messages
88
- Query Account Balance, Transaction Receipts, Topic Infos and Messages
@@ -25,6 +25,7 @@ This is a Python SDK for interacting with the Hedera Hashgraph platform. It allo
2525
- [Dissociating a Token](#dissociating-a-token)
2626
- [Transferring Tokens](#transferring-tokens)
2727
- [Deleting a Token](#deleting-a-token)
28+
- [Freezing a Token](#freezing-a-token)
2829
- [Transferring HBAR](#transferring-hbar)
2930
- [Creating a Topic](#creating-a-topic)
3031
- [Submitting a Topic Message](#submitting-a-topic-message)
@@ -115,9 +116,11 @@ OPERATOR_ID=0.0.1234xx
115116
OPERATOR_KEY=302e020100300506032b657004220420...
116117
ADMIN_KEY=302a300506032b65700321009308ecfdf...
117118
SUPPLY_KEY =302a300506032b6570032100c5e4af5..."
119+
FREEZE_KEY=302a300306072b65700321009308ecfdf...
118120
RECIPIENT_ID=0.0.789xx
119121
TOKEN_ID=0.0.100xx
120122
TOPIC_ID=0.0.200xx
123+
FREEZE_ACCOUNT_ID=0.0.100
121124
NETWORK=testnet
122125
```
123126

@@ -148,6 +151,7 @@ Token association successful.
148151
Token dissociation successful.
149152
Token minting successful.
150153
Token transfer successful.
154+
Token freeze successful.
151155
Token deletion successful.
152156
Topic creation successful.
153157
Topic Message submitted.
@@ -404,6 +408,32 @@ transaction.execute(client)
404408
transaction.execute(client)
405409
```
406410

411+
### Freezing a Token
412+
413+
#### Pythonic Syntax:
414+
```
415+
transaction = TokenFreezeTransaction(
416+
token_id=token_id
417+
account_id=account_id
418+
).freeze_with(client)
419+
420+
transaction.sign(freeze_key) # Freeze key must have been set during token creation.
421+
transaction.execute(client)
422+
```
423+
#### Method Chaining:
424+
```
425+
transaction = (
426+
TokenFreezeTransaction()
427+
.set_token_id(token_id)
428+
.set_account_id(account_id)
429+
.freeze_with(client)
430+
)
431+
432+
transaction.sign(freeze_key) # Freeze key must also have been set in Token Create
433+
transaction.execute(client)
434+
```
435+
436+
407437
### Transferring HBAR
408438

409439
#### Pythonic Syntax:

examples/token_create.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ def create_token():
2121
admin_key = PrivateKey.from_string(os.getenv('ADMIN_KEY'))
2222
supply_key = PrivateKey.from_string(os.getenv('ADMIN_KEY')) #Optional
2323

24-
24+
freeze_key = PrivateKey.from_string(os.getenv('FREEZE_KEY')) #Optional
25+
2526
client.set_operator(operator_id, operator_key)
2627

2728
transaction = (
@@ -33,9 +34,11 @@ def create_token():
3334
.set_treasury_account_id(operator_id)
3435
.set_admin_key(admin_key)
3536
.set_supply_key(supply_key)
37+
.set_freeze_key(freeze_key)
3638
.freeze_with(client)
3739
.sign(operator_key)
3840
.sign(admin_key)
41+
3942
)
4043

4144
try:

examples/token_freeze.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import os
2+
import sys
3+
from dotenv import load_dotenv
4+
5+
from hedera_sdk_python import (
6+
Client,
7+
AccountId,
8+
PrivateKey,
9+
TokenFreezeTransaction,
10+
Network,
11+
TokenId,
12+
)
13+
14+
load_dotenv()
15+
16+
def freeze_token():
17+
network = Network(network='testnet')
18+
client = Client(network)
19+
20+
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
21+
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
22+
freeze_key = PrivateKey.from_string(os.getenv('FREEZE_KEY'))
23+
token_id = TokenId.from_string(os.getenv('TOKEN_ID'))
24+
account_id = AccountId.from_string(os.getenv('FREEZE_ACCOUNT_ID'))
25+
26+
client.set_operator(operator_id, operator_key)
27+
28+
transaction = (
29+
TokenFreezeTransaction()
30+
.set_token_id(token_id)
31+
.set_account(account_id)
32+
.freeze_with(client)
33+
.sign(freeze_key)
34+
)
35+
36+
try:
37+
receipt = transaction.execute(client)
38+
if receipt is not None and receipt.status == 'SUCCESS':
39+
print(f"Token freeze successful")
40+
else:
41+
print(f"Token freeze failed.")
42+
sys.exit(1)
43+
except Exception as e:
44+
print(f"Token freeze failed: {str(e)}")
45+
sys.exit(1)
46+
47+
if __name__ == "__main__":
48+
freeze_token()

src/hiero_sdk_python/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from .tokens.token_dissociate_transaction import TokenDissociateTransaction
1717
from .tokens.token_delete_transaction import TokenDeleteTransaction
1818
from .tokens.token_mint_transaction import TokenMintTransaction
19+
from .tokens.token_freeze_transaction import TokenFreezeTransaction
1920
from .tokens.token_id import TokenId
2021

2122
# Transaction
@@ -64,6 +65,7 @@
6465
"TokenDissociateTransaction",
6566
"TokenDeleteTransaction",
6667
"TokenMintTransaction",
68+
"TokenFreezeTransaction",
6769
"TokenId",
6870

6971
# Transaction

src/hiero_sdk_python/crypto/private_key.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@
33
from cryptography.hazmat.backends import default_backend
44
from hiero_sdk_python.crypto.public_key import PublicKey
55

6-
76
class PrivateKey:
87
"""
98
Represents a private key that can be either Ed25519 or ECDSA (secp256k1).
109
"""
11-
12-
def __init__(self, private_key):
10+
def __init__(self, private_key: ec.EllipticCurvePrivateKey | ed25519.Ed25519PrivateKey):
1311
"""
1412
Initializes a PrivateKey from a cryptography PrivateKey object.
1513
"""

src/hiero_sdk_python/crypto/public_key.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ class PublicKey:
55
"""
66
Represents a public key that can be either Ed25519 or ECDSA (secp256k1).
77
"""
8-
9-
def __init__(self, public_key):
8+
def __init__(self, public_key: ec.EllipticCurvePublicKey | ed25519.Ed25519PublicKey):
109
"""
1110
Initializes a PublicKey from a cryptography PublicKey object.
1211
"""

src/hiero_sdk_python/tokens/token_create_transaction.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class TokenCreateTransaction(Transaction):
1515
"""
1616

1717
def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_supply=None,
18-
treasury_account_id=None, admin_key=None, supply_key=None):
18+
treasury_account_id=None, admin_key=None, supply_key=None, freeze_key=None):
1919
"""
2020
Initializes a new TokenCreateTransaction instance with optional keyword arguments.
2121
@@ -28,6 +28,7 @@ def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_su
2828
admin_key (PrivateKey, optional): The admin key for the token.
2929
supply_key (PrivateKey, optional): The supply key for the token.
3030
31+
freeze_key (PrivateKey, optional): The freeze key for the token.
3132
"""
3233
super().__init__()
3334
self.token_name = token_name
@@ -37,6 +38,7 @@ def __init__(self, token_name=None, token_symbol=None, decimals=None, initial_su
3738
self.treasury_account_id = treasury_account_id
3839
self.admin_key = admin_key
3940
self.supply_key = supply_key
41+
self.freeze_key = freeze_key
4042

4143
self._default_transaction_fee = 3_000_000_000
4244

@@ -75,6 +77,12 @@ def set_supply_key(self, supply_key):
7577
self.supply_key = supply_key
7678
return self
7779

80+
def set_freeze_key(self, freeze_key):
81+
self._require_not_frozen()
82+
self.freeze_key = freeze_key
83+
return self
84+
85+
7886
def build_transaction_body(self):
7987
"""
8088
Builds and returns the protobuf transaction body for token creation.
@@ -104,14 +112,21 @@ def build_transaction_body(self):
104112
supply_public_key_bytes = self.supply_key.public_key().to_bytes_raw()
105113
supply_key_proto = basic_types_pb2.Key(ed25519=supply_public_key_bytes)
106114

115+
freeze_key_proto = None
116+
if self.freeze_key:
117+
freeze_public_key_bytes = self.freeze_key.public_key().to_bytes_raw()
118+
freeze_key_proto = basic_types_pb2.Key(ed25519=freeze_public_key_bytes)
119+
107120
token_create_body = token_create_pb2.TokenCreateTransactionBody(
108121
name=self.token_name,
109122
symbol=self.token_symbol,
110123
decimals=self.decimals,
111124
initialSupply=self.initial_supply,
112125
treasury=self.treasury_account_id.to_proto(),
113126
adminKey=admin_key_proto,
114-
supplyKey=supply_key_proto
127+
supplyKey=supply_key_proto,
128+
freezeKey=freeze_key_proto
129+
115130
)
116131

117132
transaction_body = self.build_base_transaction_body()
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
from hiero_sdk_python.transaction.transaction import Transaction
2+
from hiero_sdk_python.hapi.services import token_freeze_account_pb2
3+
from hiero_sdk_python.response_code import ResponseCode
4+
5+
class TokenFreezeTransaction(Transaction):
6+
"""
7+
Represents a token freeze transaction on the Hedera network.
8+
9+
This transaction freezes a specified token for a given account.
10+
11+
Inherits from the base Transaction class and implements the required methods
12+
to build and execute a token freeze transaction.
13+
"""
14+
15+
def __init__(self, token_id=None, account_id=None):
16+
"""
17+
Initializes a new TokenFreezeTransaction instance with optional token_id and account_id.
18+
19+
Args:
20+
token_id (TokenId, optional): The ID of the token to be frozen.
21+
account_id (AccountId, optional): The ID of the account to have their token frozen.
22+
"""
23+
super().__init__()
24+
self.token_id = token_id
25+
self.account_id = account_id
26+
self._default_transaction_fee = 3_000_000_000
27+
28+
def set_token_id(self, token_id):
29+
"""
30+
Sets the ID of the token to be frozen.
31+
32+
Args:
33+
token_id (TokenId): The ID of the token to be frozen.
34+
35+
Returns:
36+
TokenFreezeTransaction: Returns self for method chaining.
37+
"""
38+
self._require_not_frozen()
39+
self.token_id = token_id
40+
return self
41+
42+
def set_account_id(self, account_id):
43+
"""
44+
Sets the ID of the account to be frozen.
45+
46+
Args:
47+
account_id (AccountId): The ID of the account to have their token frozen.
48+
49+
Returns:
50+
TokenFreezeTransaction: Returns self for method chaining.
51+
"""
52+
self._require_not_frozen()
53+
self.account_id = account_id
54+
return self
55+
56+
def build_transaction_body(self):
57+
"""
58+
Builds and returns the protobuf transaction body for token freeze.
59+
60+
Returns:
61+
TransactionBody: The protobuf transaction body containing the token freeze details.
62+
63+
Raises:
64+
ValueError: If the token ID is missing.
65+
ValueError: If the account ID is missing.
66+
"""
67+
68+
if not self.token_id:
69+
raise ValueError("Missing required TokenID.")
70+
71+
if not self.account_id:
72+
raise ValueError("Missing required AccountID.")
73+
74+
token_freeze_body = token_freeze_account_pb2.TokenFreezeAccountTransactionBody(
75+
token=self.token_id.to_proto(),
76+
account=self.account_id.to_proto()
77+
)
78+
79+
transaction_body = self.build_base_transaction_body()
80+
transaction_body.tokenFreeze.CopyFrom(token_freeze_body)
81+
82+
return transaction_body
83+
84+
def _execute_transaction(self, client, transaction_proto):
85+
"""
86+
Executes the token freeze transaction using the provided client.
87+
88+
Args:
89+
client (Client): The client instance to use for execution.
90+
transaction_proto (Transaction): The protobuf Transaction message.
91+
92+
Returns:
93+
TransactionReceipt: The receipt from the network after transaction execution.
94+
95+
Raises:
96+
Exception: If the transaction submission fails or receives an error response.
97+
"""
98+
response = client.token_stub.freezeTokenAccount(transaction_proto)
99+
100+
if response.nodeTransactionPrecheckCode != ResponseCode.OK:
101+
error_code = response.nodeTransactionPrecheckCode
102+
error_message = ResponseCode.get_name(error_code)
103+
raise Exception(f"Error during transaction submission: {error_code} ({error_message})")
104+
105+
receipt = self.get_receipt(client)
106+
return receipt
107+
108+
def get_receipt(self, client, timeout=60):
109+
"""
110+
Retrieves the receipt for the transaction.
111+
112+
Args:
113+
client (Client): The client instance.
114+
timeout (int): Maximum time in seconds to wait for the receipt.
115+
116+
Returns:
117+
TransactionReceipt: The transaction receipt from the network.
118+
119+
Raises:
120+
Exception: If the transaction ID is not set or if receipt retrieval fails.
121+
"""
122+
if self.transaction_id is None:
123+
raise Exception("Transaction ID is not set.")
124+
125+
receipt = client.get_transaction_receipt(self.transaction_id, timeout)
126+
return receipt

0 commit comments

Comments
 (0)