2323 Client ,
2424 PrivateKey ,
2525 AccountCreateTransaction ,
26+ AccountInfo ,
2627 AccountInfoQuery ,
2728 Network ,
2829 AccountId ,
@@ -49,83 +50,132 @@ def setup_client():
4950 print ("Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file." )
5051 sys .exit (1 )
5152
52- def create_account_with_separate_ecdsa_alias (client : Client ) -> None :
53- """Create an account whose alias comes from a separate ECDSA key."""
54- try :
55- print ("\n STEP 1: Generating main account key and separate ECDSA alias key..." )
56-
57- # Main account key (can be any key type, here ed25519)
58- main_private_key = PrivateKey .generate ()
59- main_public_key = main_private_key .public_key ()
60-
61- # Separate ECDSA key used only for the EVM alias
62- alias_private_key = PrivateKey .generate ("ecdsa" )
63- alias_public_key = alias_private_key .public_key ()
64- alias_evm_address = alias_public_key .to_evm_address ()
65-
66- if alias_evm_address is None :
67- print ("❌ Error: Failed to generate EVM address from alias ECDSA key." )
68- sys .exit (1 )
69-
70- print (f"✅ Main account public key: { main_public_key } " )
71- print (f"✅ Alias ECDSA public key: { alias_public_key } " )
72- print (f"✅ Alias EVM address: { alias_evm_address } " )
73-
74- print ("\n STEP 2: Creating the account with the EVM alias from the ECDSA key..." )
75-
76- # Use the helper that accepts both the main key and the ECDSA alias key
77- transaction = (
78- AccountCreateTransaction (
79- initial_balance = Hbar (5 ),
80- memo = "Account with separate ECDSA alias" ,
81- )
82- .set_key_with_alias (main_private_key , alias_public_key )
83- )
8453
85- # Freeze and sign:
86- # - operator key signs as payer (via client)
87- # - alias private key MUST sign to authorize the alias
88- transaction = (
89- transaction .freeze_with (client )
90- .sign (alias_private_key )
91- )
54+ def generate_main_and_alias_keys () -> tuple [PrivateKey , PrivateKey ]:
55+ """Generate the main account key and a separate ECDSA alias key.
56+
57+ Returns:
58+ tuple: (main_private_key, alias_private_key)
59+ """
60+ print ("\n STEP 1: Generating main account key and separate ECDSA alias key..." )
61+
62+ # Main account key (can be any key type, here ed25519)
63+ main_private_key = PrivateKey .generate ()
64+ main_public_key = main_private_key .public_key ()
65+
66+ # Separate ECDSA key used only for the EVM alias
67+ alias_private_key = PrivateKey .generate ("ecdsa" )
68+ alias_public_key = alias_private_key .public_key ()
69+ alias_evm_address = alias_public_key .to_evm_address ()
70+
71+ if alias_evm_address is None :
72+ print ("❌ Error: Failed to generate EVM address from alias ECDSA key." )
73+ sys .exit (1 )
9274
93- response = transaction .execute (client )
94- new_account_id = response .account_id
75+ print (f"✅ Main account public key: { main_public_key } " )
76+ print (f"✅ Alias ECDSA public key: { alias_public_key } " )
77+ print (f"✅ Alias EVM address: { alias_evm_address } " )
9578
96- if new_account_id is None :
97- raise RuntimeError (
98- "AccountID not found in receipt. Account may not have been created."
99- )
79+ return main_private_key , alias_private_key
10080
101- print (f"✅ Account created with ID: { new_account_id } \n " )
10281
103- account_info = (
104- AccountInfoQuery ()
105- .set_account_id (new_account_id )
106- .execute (client )
82+ def create_account_with_ecdsa_alias (
83+ client : Client , main_private_key : PrivateKey , alias_private_key : PrivateKey
84+ ) -> AccountId :
85+ """Create an account with a separate ECDSA key as the EVM alias.
86+
87+ 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.
91+
92+ Returns:
93+ AccountId: The newly created account ID.
94+ """
95+ print ("\n STEP 2: Creating the account with the EVM alias from the ECDSA key..." )
96+
97+ alias_public_key = alias_private_key .public_key ()
98+
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+ )
115+
116+ response = transaction .execute (client )
117+ new_account_id = response .account_id
118+
119+ if new_account_id is None :
120+ raise RuntimeError (
121+ "AccountID not found in receipt. Account may not have been created."
107122 )
108123
109- out = info_to_dict (account_info )
110- print ("Account Info:" )
111- print (json .dumps (out , indent = 2 ) + "\n " )
124+ print (f"✅ Account created with ID: { new_account_id } \n " )
125+ return new_account_id
112126
113- if account_info .contract_account_id is not None :
114- print (
115- f"✅ Contract Account ID (EVM alias on-chain): "
116- f"{ account_info .contract_account_id } "
117- )
118- else :
119- print ("❌ Error: Contract Account ID (alias) does not exist." )
120127
121- except Exception as error :
122- print (f"❌ Error: { error } " )
123- sys .exit (1 )
128+ def fetch_account_info (client : Client , account_id : AccountId ) -> AccountInfo :
129+ """Fetch account information from the network.
130+
131+ Args:
132+ client: The Hedera client.
133+ account_id: The account ID to query.
134+
135+ Returns:
136+ AccountInfo: The account info object.
137+ """
138+ 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
145+
146+
147+ def print_account_summary (account_info : AccountInfo ) -> None :
148+ """Print a summary of the account information.
149+
150+ Args:
151+ account_info: The account info object to display.
152+ """
153+ out = info_to_dict (account_info )
154+ print ("Account Info:" )
155+ print (json .dumps (out , indent = 2 ) + "\n " )
156+
157+ 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+ )
162+ else :
163+ print ("❌ Error: Contract Account ID (alias) does not exist." )
164+
124165
125166def main ():
126167 """Main entry point."""
127- client = setup_client ()
128- create_account_with_separate_ecdsa_alias (client )
168+ try :
169+ client = setup_client ()
170+ 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+ )
174+ account_info = fetch_account_info (client , account_id )
175+ print_account_summary (account_info )
176+ except Exception as error :
177+ print (f"❌ Error: { error } " )
178+ sys .exit (1 )
129179
130180
131181if __name__ == "__main__" :
0 commit comments