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"""
67import os
78import sys
1718 TokenCreateTransaction ,
1819 TokenAssociateTransaction ,
1920 TokenDissociateTransaction ,
21+ TokenType ,
22+ AccountInfoQuery ,
23+ ResponseCode ,
2024)
2125
2226# Load environment variables from .env file
2327load_dotenv ()
24-
2528network_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 ("\n STEP 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 ("\n STEP 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"\n STEP 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"\n STEP 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"\n STEP 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 ("\n Verifying 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"\n STEP 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
123188if __name__ == "__main__" :
124- token_dissociate ()
189+ main ()
0 commit comments