Skip to content

Commit fce4f9f

Browse files
authored
Merge branch 'hiero-ledger:main' into main
2 parents 91d86fb + 7e397ec commit fce4f9f

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
2020
- EvmAddress class
2121
- `alias`, `staked_account_id`, `staked_node_id` and `decline_staking_reward` fields to AccountCreateTransaction
2222
- `staked_account_id`, `staked_node_id` and `decline_staking_reward` fields to AccountInfo
23+
- Added `examples/token_create_transaction_supply_key.py` to demonstrate token creation with and without a supply key.
2324

2425
### Changed
2526
- Refactored token-related example scripts (`token_delete.py`, `token_dissociate.py`, etc.) for improved readability and modularity. [#370]
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
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

Comments
 (0)