Skip to content

Commit cfc86ba

Browse files
refactor(examples): modularize account_create_transaction_create_with_alias (#1030)
Signed-off-by: Aditya Shirsatrao <adityashirsatrao007@gmail.com> Signed-off-by: adityashirsatrao007 <adityashirsatrao007@gmail.com> Signed-off-by: Aditya <adityashirsatrao007@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent f9b33d9 commit cfc86ba

File tree

2 files changed

+117
-66
lines changed

2 files changed

+117
-66
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
88

99
### Added
1010

11+
- Refactored `account_create_transaction_create_with_alias.py` example by splitting monolithic function into modular functions: `generate_main_and_alias_keys()`, `create_account_with_ecdsa_alias()`, `fetch_account_info()`, `print_account_summary()` (#1016)
1112
- Modularized `transfer_transaction_fungible` example by introducing `account_balance_query()` & `transfer_transaction()`.Renamed `transfer_tokens()``main()`
12-
- Phase 2 of the inactivity-unassign bot:Automatically detects stale open pull requests (no commit activity for 21+ days), comments with a helpful InactivityBot message, closes the stale PR, and unassigns the contributor from the linked issue.
13+
- Phase 2 of the inactivity-unassign bot: Automatically detects stale open pull requests (no commit activity for 21+ days), comments with a helpful InactivityBot message, closes the stale PR, and unassigns the contributor from the linked issue.
1314
- Added `__str__()` to CustomFixedFee and updated examples and tests accordingly.
1415
- Added unit tests for `crypto_utils` (#993)
1516
- Added a github template for good first issues

examples/account/account_create_transaction_create_with_alias.py

Lines changed: 115 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
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("\nSTEP 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("\nSTEP 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("\nSTEP 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("\nSTEP 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("\nSTEP 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

125166
def 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

131181
if __name__ == "__main__":

0 commit comments

Comments
 (0)