1- """
2- Example: Create an account using a separate ECDSA key for the EVM alias.
3-
4- This demonstrates:
5- - Using a "main" key for the account
6- - Using a separate ECDSA public key as the EVM alias
7- - The need to sign the transaction with the alias private key
1+ """Example of creating an account using a separate ECDSA key for the EVM alias.
82
93Usage:
10- - uv run -m examples.account.account_create_transaction_create_with_alias
11- - python -m examples.account.account_create_transaction_create_with_alias
12- (we use -m because we use the util `info_to_dict`)
4+ uv run examples/account/account_create_transaction_create_with_alias.py
5+ python examples/account/account_create_transaction_create_with_alias.py
136"""
147
158import os
169import sys
17- import json
18- from dotenv import load_dotenv
1910
20- from examples . utils import info_to_dict
11+ from dotenv import load_dotenv
2112
2213from hiero_sdk_python import (
23- Client ,
24- PrivateKey ,
2514 AccountCreateTransaction ,
26- AccountInfo ,
27- AccountInfoQuery ,
28- Network ,
2915 AccountId ,
16+ AccountInfoQuery ,
17+ Client ,
3018 Hbar ,
19+ Network ,
20+ PrivateKey ,
3121)
3222
3323load_dotenv ()
3424network_name = os .getenv ("NETWORK" , "testnet" ).lower ()
3525
3626
3727def setup_client ():
38- """Setup Client."""
28+ """Initialize client and return operator credentials.
29+
30+ Returns:
31+ tuple: A tuple containing (Client, operator_id, operator_key).
32+
33+ """
3934 network = Network (network_name )
4035 print (f"Connecting to Hedera { network_name } network!" )
4136 client = Client (network )
@@ -45,25 +40,25 @@ def setup_client():
4540 operator_key = PrivateKey .from_string (os .getenv ("OPERATOR_KEY" , "" ))
4641 client .set_operator (operator_id , operator_key )
4742 print (f"Client set up with operator id { client .operator_account_id } " )
48- return client
43+ return client , operator_id , operator_key
44+
4945 except Exception :
5046 print ("Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file." )
5147 sys .exit (1 )
5248
5349
54- def generate_main_and_alias_keys () -> tuple [ PrivateKey , PrivateKey ] :
50+ def generate_main_and_alias_keys ():
5551 """Generate the main account key and a separate ECDSA alias key.
5652
5753 Returns:
5854 tuple: (main_private_key, alias_private_key)
55+
5956 """
6057 print ("\n STEP 1: Generating main account key and separate ECDSA alias key..." )
6158
62- # Main account key (can be any key type, here ed25519)
6359 main_private_key = PrivateKey .generate ()
6460 main_public_key = main_private_key .public_key ()
6561
66- # Separate ECDSA key used only for the EVM alias
6762 alias_private_key = PrivateKey .generate ("ecdsa" )
6863 alias_public_key = alias_private_key .public_key ()
6964 alias_evm_address = alias_public_key .to_evm_address ()
@@ -79,100 +74,90 @@ def generate_main_and_alias_keys() -> tuple[PrivateKey, PrivateKey]:
7974 return main_private_key , alias_private_key
8075
8176
82- def create_account_with_ecdsa_alias (
83- client : Client , main_private_key : PrivateKey , alias_private_key : PrivateKey
84- ) -> AccountId :
77+ def create_account_with_ecdsa_alias (client , main_private_key , alias_private_key , operator_key ):
8578 """Create an account with a separate ECDSA key as the EVM alias.
8679
8780 Args:
88- client: The Hedera client.
89- main_private_key: The main account private key.
90- alias_private_key: The ECDSA private key for the EVM alias.
81+ client: The initialized Client instance.
82+ main_private_key: The private key for the main account.
83+ alias_private_key: The private key for the alias (needed for signing).
84+ operator_key: The operator's private key (payer).
9185
9286 Returns:
93- AccountId: The newly created account ID.
87+ AccountId: The ID of the newly created account.
88+
9489 """
9590 print ("\n STEP 2: Creating the account with the EVM alias from the ECDSA key..." )
9691
9792 alias_public_key = alias_private_key .public_key ()
9893
99- # Use the helper that accepts both the main key and the ECDSA alias key
100- transaction = (
101- AccountCreateTransaction (
102- initial_balance = Hbar (5 ),
103- memo = "Account with separate ECDSA alias" ,
104- )
105- .set_key_with_alias (main_private_key , alias_public_key )
106- )
107-
108- # Freeze and sign:
109- # - operator key signs as payer (via client)
110- # - alias private key MUST sign to authorize the alias
111- transaction = (
112- transaction .freeze_with (client )
113- .sign (alias_private_key )
114- )
94+ transaction = AccountCreateTransaction (
95+ initial_balance = Hbar (5 ),
96+ memo = "Account with separate ECDSA alias" ,
97+ ).set_key_with_alias (main_private_key , alias_public_key )
98+
99+ # Freeze and sign with BOTH keys
100+ transaction = transaction .freeze_with (client ).sign (alias_private_key ).sign (operator_key )
115101
116102 response = transaction .execute (client )
117- new_account_id = response .account_id
118103
104+ # Safe retrieval of account ID
105+ new_account_id = response .account_id
119106 if new_account_id is None :
120- raise RuntimeError (
121- "AccountID not found in receipt. Account may not have been created."
122- )
107+ try :
108+ new_account_id = response .get_receipt (client ).account_id
109+ except Exception :
110+ raise RuntimeError ("AccountID not found. Account may not have been created." )
123111
124112 print (f"✅ Account created with ID: { new_account_id } \n " )
125113 return new_account_id
126114
127115
128- def fetch_account_info (client : Client , account_id : AccountId ) -> AccountInfo :
116+ def fetch_account_info (client , account_id ) :
129117 """Fetch account information from the network.
130118
131119 Args:
132- client: The Hedera client .
133- account_id: The account ID to query.
120+ client: The initialized Client instance .
121+ account_id: The ID of the account to query.
134122
135123 Returns:
136- AccountInfo: The account info object.
124+ AccountInfo: The account information object.
125+
137126 """
138127 print ("\n STEP 3: Fetching account information..." )
139- account_info = (
140- AccountInfoQuery ()
141- .set_account_id (account_id )
142- .execute (client )
143- )
144- return account_info
128+ return AccountInfoQuery ().set_account_id (account_id ).execute (client )
145129
146130
147- def print_account_summary (account_info : AccountInfo ) -> None :
131+ def print_account_summary (account_info ) :
148132 """Print a summary of the account information.
149133
150134 Args:
151- account_info: The account info object to display.
135+ account_info: The AccountInfo object to display.
136+
152137 """
153- out = info_to_dict ( account_info )
154- print ("Account Info:" )
155- print (json . dumps ( out , indent = 2 ) + " \n " )
138+ print ( "--- Account Info ---" )
139+ print (account_info )
140+ print ("-------------------- \n " )
156141
157142 if account_info .contract_account_id is not None :
158- print (
159- f"✅ Contract Account ID (EVM alias on-chain): "
160- f"{ account_info .contract_account_id } "
161- )
143+ print (f"✅ Contract Account ID (EVM alias on-chain): { account_info .contract_account_id } " )
162144 else :
163145 print ("❌ Error: Contract Account ID (alias) does not exist." )
164146
165147
166148def main ():
167- """Main entry point ."""
149+ """Run the example workflow ."""
168150 try :
169- client = setup_client ()
151+ client , _ , operator_key = setup_client ()
152+
170153 main_private_key , alias_private_key = generate_main_and_alias_keys ()
171- account_id = create_account_with_ecdsa_alias (
172- client , main_private_key , alias_private_key
173- )
154+
155+ account_id = create_account_with_ecdsa_alias ( client , main_private_key , alias_private_key , operator_key )
156+
174157 account_info = fetch_account_info (client , account_id )
158+
175159 print_account_summary (account_info )
160+
176161 except Exception as error :
177162 print (f"❌ Error: { error } " )
178163 sys .exit (1 )
0 commit comments