Skip to content

Commit 12cee39

Browse files
authored
chore: refactor token examples (#378)
Signed-off-by: MonaaEid <[email protected]>
1 parent 01e2369 commit 12cee39

File tree

7 files changed

+395
-194
lines changed

7 files changed

+395
-194
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
1111

1212

1313
### Changed
14+
- Refactored token-related example scripts (`token_delete.py`, `token_dissociate.py`, etc.) for improved readability and modularity. [#370]
1415

1516

1617
### Fixed

examples/token_delete.py

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
"""
2-
uv run examples/token_delete.py
3-
python examples/token_delete.py
1+
# uv run examples/token_delete.py
2+
# python examples/token_delete.py
43

54
"""
5+
A full example that creates a token and then immediately deletes it.
6+
"""
7+
68
import os
79
import sys
810
from dotenv import load_dotenv
@@ -18,40 +20,41 @@
1820

1921
# Load environment variables from .env file
2022
load_dotenv()
21-
2223
network_name = os.getenv('NETWORK', 'testnet').lower()
2324

24-
def create_and_delete_token():
25-
"""
26-
A full example that creates a token and then immediately deletes it.
27-
"""
28-
# 1. Setup Client
29-
# =================================================================
25+
def setup_client():
26+
"""Setup Client """
3027
network = Network(network_name)
3128
print(f"Connecting to Hedera {network_name} network!")
3229
client = Client(network)
3330

3431
# Get the operator account from the .env file
3532
try:
3633
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID', ''))
37-
# NOTE: Assumes your operator key is a raw Ed25519 key
3834
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY', ''))
35+
# Set the operator (payer) account for the client
36+
client.set_operator(operator_id, operator_key)
37+
print(f"Client set up with operator id {client.operator_account_id}")
38+
return client, operator_id, operator_key
3939
except (TypeError, ValueError):
4040
print("Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file.")
4141
sys.exit(1)
42+
4243

43-
client.set_operator(operator_id, operator_key)
44-
print(f"Client set up with operator id {client.operator_account_id}")
44+
def generate_admin_key():
45+
"""Generate a new admin key within the script:
46+
This key will be used to create the token with admin privileges
47+
"""
4548

46-
# 2. Generate a new admin key within the script
47-
# =================================================================
4849
print("\nGenerating a new admin key for the token...")
49-
admin_key = PrivateKey.generate_ed25519()
50+
admin_key = PrivateKey.generate(os.getenv('KEY_TYPE', 'ed25519'))
5051
print("Admin key generated successfully.")
52+
return admin_key
53+
54+
def create_new_token(client, operator_id, operator_key, admin_key):
55+
""" Create the Token"""
5156
token_id_to_delete = None
5257

53-
# 3. Create the Token
54-
# =================================================================
5558
try:
5659
print("\nSTEP 1: Creating a new token...")
5760
create_tx = (
@@ -69,14 +72,18 @@ def create_and_delete_token():
6972
create_receipt = create_tx.execute(client)
7073
token_id_to_delete = create_receipt.token_id
7174
print(f"✅ Success! Created token with ID: {token_id_to_delete}")
75+
return token_id_to_delete
7276

73-
except Exception as e:
77+
except (ValueError, TypeError) as e:
7478
print(f"❌ Error creating token: {e}")
7579
sys.exit(1)
7680

7781

78-
# 4. Delete the Token
79-
# =================================================================
82+
def delete_token(admin_key, token_id_to_delete, client, operator_key):
83+
"""
84+
Delete the Token we just created
85+
"""
86+
8087
try:
8188
print(f"\nSTEP 2: Deleting token {token_id_to_delete}...")
8289
delete_tx = (
@@ -87,13 +94,26 @@ def create_and_delete_token():
8794
.sign(admin_key) # Sign with the same admin key used to create it
8895
)
8996

90-
delete_receipt = delete_tx.execute(client)
91-
print(f"✅ Success! Token deleted.")
97+
delete_tx.execute(client)
98+
print("✅ Success! Token deleted.")
9299

93-
except Exception as e:
100+
except (ValueError, TypeError) as e:
94101
print(f"❌ Error deleting token: {e}")
95102
sys.exit(1)
96103

104+
def main():
105+
"""
106+
1. Call create_new_token() to create a new token and get its admin key, token ID, client, and operator key.
107+
2. Build a TokenDeleteTransaction using the token ID.
108+
3. Freeze the transaction with the client.
109+
4. Sign the transaction with both the operator key and the admin key.
110+
5. Execute the transaction to delete the token.
111+
6. Print the result or handle any errors.
112+
"""
113+
client, operator_id, operator_key = setup_client()
114+
admin_key = generate_admin_key()
115+
token_id_to_delete = create_new_token(client, operator_id, operator_key, admin_key)
116+
delete_token(admin_key, token_id_to_delete, client, operator_key)
97117

98118
if __name__ == "__main__":
99-
create_and_delete_token()
119+
main()

examples/token_dissociate.py

Lines changed: 110 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
# uv run examples/token_dissociate.py
2+
# python examples/token_dissociate.py
13
"""
2-
uv run examples/token_dissociate.py
3-
python examples/token_dissociate.py
4-
4+
A full example that creates an account, two tokens, associates them,
5+
and finally dissociates them.
56
"""
67
import os
78
import sys
@@ -17,19 +18,17 @@
1718
TokenCreateTransaction,
1819
TokenAssociateTransaction,
1920
TokenDissociateTransaction,
21+
TokenType,
22+
AccountInfoQuery,
23+
ResponseCode,
2024
)
2125

2226
# Load environment variables from .env file
2327
load_dotenv()
24-
2528
network_name = os.getenv('NETWORK', 'testnet').lower()
26-
def token_dissociate():
27-
"""
28-
A full example that creates an account, two tokens, associates them,
29-
and finally dissociates them.
30-
"""
31-
# 1. Setup Client
32-
# =================================================================
29+
30+
def setup_client():
31+
"""Setup Client"""
3332
network = Network(network_name)
3433
print(f"Connecting to Hedera {network_name} network!")
3534
client = Client(network)
@@ -38,16 +37,19 @@ def token_dissociate():
3837
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID', ''))
3938
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY', ''))
4039
client.set_operator(operator_id, operator_key)
40+
print(f"Client set up with operator id {client.operator_account_id}")
41+
return client, operator_id, operator_key
42+
4143
except (TypeError, ValueError):
4244
print("❌ Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file.")
4345
sys.exit(1)
4446

45-
print(f"Client set up with operator id {client.operator_account_id}")
4647

47-
# 2. Create a new account to associate/dissociate with
48-
# =================================================================
48+
def create_new_account(client, operator_id, operator_key):
49+
"""Create a new account to associate/dissociate with tokens"""
4950
print("\nSTEP 1: Creating a new account...")
50-
recipient_key = PrivateKey.generate("ed25519")
51+
recipient_key = PrivateKey.generate(os.getenv('KEY_TYPE', 'ed25519'))
52+
5153
try:
5254
# Build the transaction
5355
tx = (
@@ -60,65 +62,128 @@ def token_dissociate():
6062
receipt = tx.freeze_with(client).sign(operator_key).execute(client)
6163
recipient_id = receipt.account_id
6264
print(f"✅ Success! Created new account with ID: {recipient_id}")
63-
except Exception as e:
65+
return client, operator_key, recipient_id, recipient_key, operator_id
66+
67+
except (ValueError, RuntimeError) as e:
6468
print(f"❌ Error creating new account: {e}")
6569
sys.exit(1)
66-
67-
# 3. Create two new tokens
68-
# =================================================================
70+
def create_token(client, operator_key, recipient_id, recipient_key, operator_id):
71+
"""Create two new tokens (one NFT and one fungible) for demonstration purposes. """
6972
print("\nSTEP 2: Creating two new tokens...")
7073
try:
71-
# Create First Token
72-
tx1 = TokenCreateTransaction().set_token_name("First Token").set_token_symbol("TKA").set_initial_supply(1).set_treasury_account_id(operator_id)
73-
receipt1 = tx1.freeze_with(client).sign(operator_key).execute(client)
74-
token_id_1 = receipt1.token_id
75-
76-
# Create Second Token
77-
tx2 = TokenCreateTransaction().set_token_name("Second Token").set_token_symbol("TKB").set_initial_supply(1).set_treasury_account_id(operator_id)
78-
receipt2 = tx2.freeze_with(client).sign(operator_key).execute(client)
79-
token_id_2 = receipt2.token_id
80-
81-
print(f"✅ Success! Created tokens: {token_id_1} and {token_id_2}")
82-
except Exception as e:
74+
# Generate supply key for NFT
75+
supply_key = PrivateKey.generate_ed25519()
76+
# Create NFT Token
77+
nft_tx = (
78+
TokenCreateTransaction()
79+
.set_token_name("NFT Token")
80+
.set_token_symbol("NFTK")
81+
.set_token_type(TokenType.NON_FUNGIBLE_UNIQUE)
82+
.set_initial_supply(0)
83+
.set_treasury_account_id(operator_id)
84+
.set_supply_key(supply_key)
85+
)
86+
nft_receipt = nft_tx.freeze_with(client).sign(operator_key).execute(client)
87+
nft_token_id = nft_receipt.token_id
88+
89+
# Create Fungible Token
90+
fungible_tx = (
91+
TokenCreateTransaction()
92+
.set_token_name("Fungible Token")
93+
.set_token_symbol("FTK")
94+
.set_initial_supply(1)
95+
.set_treasury_account_id(operator_id)
96+
)
97+
fungible_receipt = fungible_tx.freeze_with(client).sign(operator_key).execute(client)
98+
fungible_token_id = fungible_receipt.token_id
99+
100+
print(f"✅ Success! Created NFT token: {nft_token_id} and fungible token: {fungible_token_id}")
101+
return client, nft_token_id, fungible_token_id, recipient_id, recipient_key
102+
103+
except (ValueError, RuntimeError) as e:
83104
print(f"❌ Error creating tokens: {e}")
84105
sys.exit(1)
85106

86-
# 4. Associate the tokens with the new account
87-
# =================================================================
88-
print(f"\nSTEP 3: Associating tokens with account {recipient_id}...")
107+
def token_associate(client, nft_token_id, fungible_token_id, recipient_id, recipient_key):
108+
"""
109+
Associate the tokens with the new account.
110+
111+
Note: Tokens must be associated with an account before they can be used or dissociated.
112+
Association is a prerequisite for holding, transferring, or later dissociating tokens.
113+
"""
114+
115+
print(f"\nSTEP 3: Associating NFT and fungible tokens with account {recipient_id}...")
116+
print("Note: Tokens must be associated with an account before they can be used or dissociated.")
89117
try:
90118
receipt = (
91119
TokenAssociateTransaction()
92120
.set_account_id(recipient_id)
93-
.add_token_id(token_id_1)
94-
.add_token_id(token_id_2)
121+
.add_token_id(nft_token_id)
122+
.add_token_id(fungible_token_id)
95123
.freeze_with(client)
96124
.sign(recipient_key) # Recipient must sign to approve
97125
.execute(client)
98126
)
99127
print(f"✅ Success! Token association complete. Status: {receipt.status}")
100-
except Exception as e:
128+
return client, nft_token_id, fungible_token_id, recipient_id, recipient_key
129+
except (ValueError, RuntimeError) as e:
101130
print(f"❌ Error associating tokens: {e}")
102131
sys.exit(1)
103132

104-
# 5. Dissociate the tokens from the new account
105-
# =================================================================
106-
print(f"\nSTEP 4: Dissociating tokens from account {recipient_id}...")
133+
def verify_dissociation(client, nft_token_id, fungible_token_id, recipient_id):
134+
"""Verify that the specified tokens are dissociated from the account."""
135+
print("\nVerifying token dissociation...")
136+
info = AccountInfoQuery().set_account_id(recipient_id).execute(client)
137+
associated_tokens = [rel.token_id for rel in getattr(info, 'token_relationships', [])]
138+
if nft_token_id not in associated_tokens and fungible_token_id not in associated_tokens:
139+
print("✅ Verified: Both tokens are dissociated from the account.")
140+
else:
141+
print("❌ Verification failed: Some tokens are still associated.")
142+
143+
def token_dissociate(client, nft_token_id, fungible_token_id, recipient_id, recipient_key):
144+
"""
145+
Dissociate the tokens from the new account.
146+
147+
Why dissociate?
148+
- To remove unwanted tokens from your account
149+
- To reduce account costs (some tokens may incur fees)
150+
- For security or privacy reasons
151+
- To comply with business or regulatory requirements
152+
"""
153+
154+
print(f"\nSTEP 4: Dissociating NFT and fungible tokens from account {recipient_id}...")
107155
try:
108156
receipt = (
109157
TokenDissociateTransaction()
110158
.set_account_id(recipient_id)
111-
.add_token_id(token_id_1)
112-
.add_token_id(token_id_2)
159+
.add_token_id(nft_token_id)
160+
.add_token_id(fungible_token_id)
113161
.freeze_with(client)
114162
.sign(recipient_key) # Recipient must sign to approve
115163
.execute(client)
116164
)
117-
print(f"✅ Success! Token dissociation complete.")
118-
except Exception as e:
165+
print(f"✅ Success! Token dissociation complete for both NFT and fungible tokens, Status: {ResponseCode(receipt.status).name}")
166+
167+
except (ValueError, RuntimeError) as e:
119168
print(f"❌ Error dissociating tokens: {e}")
120169
sys.exit(1)
121170

171+
def main():
172+
"""
173+
1-create new account
174+
2-create two tokens
175+
3-associate the tokens with the new account
176+
4-dissociate the tokens from the new account
177+
5-verify dissociation
178+
"""
179+
client, operator_id, operator_key = setup_client()
180+
client, operator_key, recipient_id, recipient_key, operator_id =create_new_account(client, operator_id, operator_key)
181+
client, nft_token_id, fungible_token_id, recipient_id, recipient_key = create_token(client, operator_key, recipient_id, recipient_key, operator_id)
182+
token_associate(client, nft_token_id, fungible_token_id, recipient_id, recipient_key)
183+
token_dissociate(client, nft_token_id, fungible_token_id, recipient_id, recipient_key)
184+
# Optional: Verify dissociation
185+
verify_dissociation(client, nft_token_id, fungible_token_id, recipient_id)
186+
122187

123188
if __name__ == "__main__":
124-
token_dissociate()
189+
main()

0 commit comments

Comments
 (0)