1+ """
2+ This example demonstrates the Purpose of the Supply Key for token management using Hiero SDK Python.
3+
4+ It shows:
5+ 1. Creating a FUNGIBLE token WITHOUT a supply key (Fixed Supply).
6+ 2. Attempting to mint more of that token (Fails, because no supply key exists).
7+ 3. Creating an NFT token WITH a supply key.
8+ 4. Successfully minting tokens using the supply key.
9+ 5. Verifying the supply using TokenInfoQuery.
10+
11+ Required environment variables:
12+ - OPERATOR_ID, OPERATOR_KEY
13+
14+ Usage:
15+ uv run examples/token_create_transaction_supply_key.py
16+ """
17+
18+ import os
19+ import sys
20+ from dotenv import load_dotenv
21+
22+ from hiero_sdk_python import (
23+ Client ,
24+ AccountId ,
25+ PrivateKey ,
26+ Network ,
27+ TokenCreateTransaction ,
28+ TokenMintTransaction ,
29+ TokenInfoQuery ,
30+ )
31+
32+ from hiero_sdk_python .response_code import ResponseCode
33+ from hiero_sdk_python .tokens .token_type import TokenType
34+ from hiero_sdk_python .tokens .supply_type import SupplyType
35+
36+ load_dotenv ()
37+ network_name = os .getenv ('NETWORK' , 'testnet' ).lower ()
38+
39+
40+ def setup_client ():
41+ """Initialize and set up the client with operator account"""
42+ network = Network (network_name )
43+ print (f" <===> Connecting to Hedera { network_name } network <===> " )
44+ client = Client (network )
45+
46+ try :
47+ operator_id = AccountId .from_string (os .getenv ('OPERATOR_ID' , '' ))
48+ operator_key = PrivateKey .from_string (os .getenv ('OPERATOR_KEY' , '' ))
49+ client .set_operator (operator_id , operator_key )
50+ print (f"Client set up with operator id { client .operator_account_id } " )
51+ return client , operator_id , operator_key
52+
53+ except (TypeError , ValueError ):
54+ print ("Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file." )
55+ sys .exit (1 )
56+
57+
58+ def create_token_no_supply_key (client , operator_id , operator_key ):
59+ """
60+ Create a FUNGIBLE token WITHOUT a supply key.
61+ We use Fungible because creating an NFT without a supply key is forbidden
62+ (it would result in a permanently 0-supply, useless token).
63+ """
64+ print ("\n --- Scenario 1: Token WITHOUT Supply Key ---" )
65+ print ("Creating a Fungible token with NO supply key (Fixed Supply)..." )
66+
67+ transaction = (
68+ TokenCreateTransaction ()
69+ .set_token_name ("Fixed Supply Token" )
70+ .set_token_symbol ("FST" )
71+ .set_token_type (TokenType .FUNGIBLE_COMMON )
72+ .set_initial_supply (1000 )
73+ .set_decimals (0 )
74+ .set_treasury_account_id (operator_id )
75+ .freeze_with (client )
76+ )
77+
78+ transaction .sign (operator_key )
79+
80+ try :
81+ reciept = transaction .execute (client )
82+ if reciept .status != ResponseCode .SUCCESS :
83+ print (f"Token creation failed with status: { ResponseCode (reciept .status ).name } " )
84+ sys .exit (1 )
85+
86+ token_id = reciept .token_id
87+ print (f" ✅ Token created successfully with ID: { token_id } " )
88+ return token_id
89+
90+ except Exception as e :
91+ print (f"Error during token creation as: { e } ." )
92+ sys .exit (1 )
93+
94+
95+ def demonstrate_mint_fail (client , token_id ):
96+ """
97+ Attempt to mint more tokens when no supply key exists.
98+ This is expected to FAIL.
99+ """
100+ print (f"Attempting to mint more to { token_id } (Expected to FAIL)..." )
101+
102+ transaction = (
103+ TokenMintTransaction ()
104+ .set_token_id (token_id )
105+ .set_amount (100 ) # Trying to mint 100 more fungible tokens
106+ .freeze_with (client )
107+ )
108+
109+ try :
110+ receipt = transaction .execute (client )
111+ if receipt .status == ResponseCode .TOKEN_HAS_NO_SUPPLY_KEY :
112+ print (f" --> Mint failed as expected! Status: { ResponseCode (receipt .status ).name } " )
113+ else :
114+ print (f"Mint failed with status: { ResponseCode (receipt .status ).name } " )
115+
116+ except Exception as e :
117+ print (f"✅ Mint failed as expected! Error: { e } " )
118+
119+
120+ def create_token_with_supply_key (client , operator_id , operator_key ):
121+ """
122+ Create a Non-Fungible token (NFT) WITH a supply key.
123+ """
124+ print ("\n --- Scenario 2: Token WITH Supply Key ---" )
125+
126+ # Generate a specific supply key
127+ supply_key = PrivateKey .generate_ed25519 ()
128+ print (" ---> Generated new Supply Key." )
129+
130+ print (" ---> Creating an NFT token WITH supply key..." )
131+
132+ transaction = (
133+ TokenCreateTransaction ()
134+ .set_token_name ("With Supply Key NFT" )
135+ .set_token_symbol ("WSK" )
136+ .set_token_type (TokenType .NON_FUNGIBLE_UNIQUE )
137+ .set_supply_type (SupplyType .FINITE )
138+ .set_max_supply (100 )
139+ .set_treasury_account_id (operator_id )
140+ .set_supply_key (supply_key ) # <--- Setting the supply key
141+ .freeze_with (client )
142+ )
143+
144+ # Sign with operator and supply key
145+ transaction .sign (operator_key )
146+ transaction .sign (supply_key )
147+
148+ try :
149+ receipt = transaction .execute (client )
150+ if receipt .status != ResponseCode .SUCCESS :
151+ print (f"Token creation failed with status: { ResponseCode (receipt .status ).name } " )
152+ sys .exit (1 )
153+
154+ token_id = receipt .token_id
155+ print (f" ✅ Token created successfully with ID: { token_id } " )
156+ return token_id , supply_key
157+
158+ except Exception as e :
159+ print (f"Error during token Creation as :{ e } ." )
160+ sys .exit (1 )
161+
162+
163+ def demonstrate_mint_success (client , token_id , supply_key ):
164+ """
165+ Mint a token using the valid supply key.
166+ For NFTs, minting involve setting metadata for each unique serial number been created.
167+ """
168+ print (f"Attempting to mint NFT to { token_id } using Supply Key..." )
169+
170+ transaction = (
171+ TokenMintTransaction ()
172+ .set_token_id (token_id )
173+ .set_metadata ([b"NFT Serial 1" , b"NFT Serial 2" ])
174+ .freeze_with (client )
175+ )
176+
177+ ## #### =>: Must sign with the supply key!
178+ transaction .sign (supply_key )
179+
180+ receipt = transaction .execute (client )
181+
182+ if receipt .status != ResponseCode .SUCCESS :
183+ print (f" ❌ Mint failed with status: { ResponseCode (receipt .status ).name } " )
184+ return
185+
186+ print (f"✅ Mint Successful! New Serials: { receipt .serial_numbers } " )
187+
188+
189+ def verify_token_info (client , token_id ):
190+ """Query token info to see total supply."""
191+ print (f"Querying Token Info for { token_id } ..." )
192+ info = TokenInfoQuery ().set_token_id (token_id ).execute (client )
193+
194+ print (f" - Total Supply: { info .total_supply } " )
195+ print (f" - Supply Key Set: { info .supply_key is not None } " )
196+
197+
198+ def main ():
199+ """
200+ Main execution flow.
201+ """
202+ client , operator_id , operator_key = setup_client ()
203+
204+ # 1. Demonstrate Failure (No Supply Key)
205+ # Note: Using Fungible token because NFT requires Supply Key at creation
206+ token_id_no_key = create_token_no_supply_key (client , operator_id , operator_key )
207+ demonstrate_mint_fail (client , token_id_no_key )
208+
209+ # 2. Demonstrate Success (With Supply Key)
210+ token_id_with_key , supply_key = create_token_with_supply_key (client , operator_id , operator_key )
211+ demonstrate_mint_success (client , token_id_with_key , supply_key )
212+ verify_token_info (client , token_id_with_key )
213+
214+ print ("\n <---> Supply key demonstration completed <---> " )
215+
216+
217+ if __name__ == "__main__" :
218+ main ()
0 commit comments