From b3c17c4de97546f6fe2e33cdf512674fcdc9edb0 Mon Sep 17 00:00:00 2001 From: adityashirsatrao007 Date: Wed, 10 Dec 2025 22:45:41 +0530 Subject: [PATCH 1/3] refactor(examples): modularize account_create_transaction_create_with_alias (#1016) Split monolithic create_account_with_separate_ecdsa_alias() into separate functions: - generate_main_and_alias_keys(): Generate main and ECDSA alias keys - create_account_with_ecdsa_alias(): Create account with the alias - fetch_account_info(): Query account information - print_account_summary(): Display account details These functions are now called from main() for better readability and maintainability. Signed-off-by: Aditya Shirsatrao Signed-off-by: adityashirsatrao007 --- CHANGELOG.md | 1 + ...nt_create_transaction_create_with_alias.py | 179 +++++++++++------- 2 files changed, 115 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5c0f48a..7b1363fbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. ### Added +- 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) - Modularized `transfer_transaction_fungible` example by introducing `account_balance_query()` & `transfer_transaction()`.Renamed `transfer_tokens()` → `main()` - 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. - Added `__str__()` to CustomFixedFee and updated examples and tests accordingly. diff --git a/examples/account/account_create_transaction_create_with_alias.py b/examples/account/account_create_transaction_create_with_alias.py index 9d8e6cade..f44cf67a1 100644 --- a/examples/account/account_create_transaction_create_with_alias.py +++ b/examples/account/account_create_transaction_create_with_alias.py @@ -49,83 +49,132 @@ def setup_client(): print("Error: Please check OPERATOR_ID and OPERATOR_KEY in your .env file.") sys.exit(1) -def create_account_with_separate_ecdsa_alias(client: Client) -> None: - """Create an account whose alias comes from a separate ECDSA key.""" - try: - print("\nSTEP 1: Generating main account key and separate ECDSA alias key...") - - # Main account key (can be any key type, here ed25519) - main_private_key = PrivateKey.generate() - main_public_key = main_private_key.public_key() - - # Separate ECDSA key used only for the EVM alias - alias_private_key = PrivateKey.generate("ecdsa") - alias_public_key = alias_private_key.public_key() - alias_evm_address = alias_public_key.to_evm_address() - - if alias_evm_address is None: - print("❌ Error: Failed to generate EVM address from alias ECDSA key.") - sys.exit(1) - - print(f"✅ Main account public key: {main_public_key}") - print(f"✅ Alias ECDSA public key: {alias_public_key}") - print(f"✅ Alias EVM address: {alias_evm_address}") - - print("\nSTEP 2: Creating the account with the EVM alias from the ECDSA key...") - - # Use the helper that accepts both the main key and the ECDSA alias key - transaction = ( - AccountCreateTransaction( - initial_balance=Hbar(5), - memo="Account with separate ECDSA alias", - ) - .set_key_with_alias(main_private_key, alias_public_key) - ) - # Freeze and sign: - # - operator key signs as payer (via client) - # - alias private key MUST sign to authorize the alias - transaction = ( - transaction.freeze_with(client) - .sign(alias_private_key) - ) +def generate_main_and_alias_keys() -> tuple[PrivateKey, PrivateKey]: + """Generate the main account key and a separate ECDSA alias key. + + Returns: + tuple: (main_private_key, alias_private_key) + """ + print("\nSTEP 1: Generating main account key and separate ECDSA alias key...") + + # Main account key (can be any key type, here ed25519) + main_private_key = PrivateKey.generate() + main_public_key = main_private_key.public_key() + + # Separate ECDSA key used only for the EVM alias + alias_private_key = PrivateKey.generate("ecdsa") + alias_public_key = alias_private_key.public_key() + alias_evm_address = alias_public_key.to_evm_address() + + if alias_evm_address is None: + print("❌ Error: Failed to generate EVM address from alias ECDSA key.") + sys.exit(1) - response = transaction.execute(client) - new_account_id = response.account_id + print(f"✅ Main account public key: {main_public_key}") + print(f"✅ Alias ECDSA public key: {alias_public_key}") + print(f"✅ Alias EVM address: {alias_evm_address}") - if new_account_id is None: - raise RuntimeError( - "AccountID not found in receipt. Account may not have been created." - ) + return main_private_key, alias_private_key - print(f"✅ Account created with ID: {new_account_id}\n") - account_info = ( - AccountInfoQuery() - .set_account_id(new_account_id) - .execute(client) +def create_account_with_ecdsa_alias( + client: Client, main_private_key: PrivateKey, alias_private_key: PrivateKey +) -> AccountId: + """Create an account with a separate ECDSA key as the EVM alias. + + Args: + client: The Hedera client. + main_private_key: The main account private key. + alias_private_key: The ECDSA private key for the EVM alias. + + Returns: + AccountId: The newly created account ID. + """ + print("\nSTEP 2: Creating the account with the EVM alias from the ECDSA key...") + + alias_public_key = alias_private_key.public_key() + + # Use the helper that accepts both the main key and the ECDSA alias key + transaction = ( + AccountCreateTransaction( + initial_balance=Hbar(5), + memo="Account with separate ECDSA alias", + ) + .set_key_with_alias(main_private_key, alias_public_key) + ) + + # Freeze and sign: + # - operator key signs as payer (via client) + # - alias private key MUST sign to authorize the alias + transaction = ( + transaction.freeze_with(client) + .sign(alias_private_key) + ) + + response = transaction.execute(client) + new_account_id = response.account_id + + if new_account_id is None: + raise RuntimeError( + "AccountID not found in receipt. Account may not have been created." ) - out = info_to_dict(account_info) - print("Account Info:") - print(json.dumps(out, indent=2) + "\n") + print(f"✅ Account created with ID: {new_account_id}\n") + return new_account_id - if account_info.contract_account_id is not None: - print( - f"✅ Contract Account ID (EVM alias on-chain): " - f"{account_info.contract_account_id}" - ) - else: - print("❌ Error: Contract Account ID (alias) does not exist.") - except Exception as error: - print(f"❌ Error: {error}") - sys.exit(1) +def fetch_account_info(client: Client, account_id: AccountId): + """Fetch account information from the network. + + Args: + client: The Hedera client. + account_id: The account ID to query. + + Returns: + The account info object. + """ + print("STEP 3: Fetching account information...") + account_info = ( + AccountInfoQuery() + .set_account_id(account_id) + .execute(client) + ) + return account_info + + +def print_account_summary(account_info) -> None: + """Print a summary of the account information. + + Args: + account_info: The account info object to display. + """ + out = info_to_dict(account_info) + print("Account Info:") + print(json.dumps(out, indent=2) + "\n") + + if account_info.contract_account_id is not None: + print( + f"✅ Contract Account ID (EVM alias on-chain): " + f"{account_info.contract_account_id}" + ) + else: + print("❌ Error: Contract Account ID (alias) does not exist.") + def main(): """Main entry point.""" - client = setup_client() - create_account_with_separate_ecdsa_alias(client) + try: + client = setup_client() + main_private_key, alias_private_key = generate_main_and_alias_keys() + account_id = create_account_with_ecdsa_alias( + client, main_private_key, alias_private_key + ) + account_info = fetch_account_info(client, account_id) + print_account_summary(account_info) + except Exception as error: + print(f"❌ Error: {error}") + sys.exit(1) if __name__ == "__main__": From ded1f64e78c45543690a834590e0a7d00d93f9c7 Mon Sep 17 00:00:00 2001 From: adityashirsatrao007 Date: Wed, 10 Dec 2025 23:06:32 +0530 Subject: [PATCH 2/3] fix: address review feedback - Add AccountInfo import - Add return type annotation to fetch_account_info - Add type annotation to print_account_summary parameter - Add newline to STEP 3 for consistent formatting Signed-off-by: adityashirsatrao007 --- .../account_create_transaction_create_with_alias.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/account/account_create_transaction_create_with_alias.py b/examples/account/account_create_transaction_create_with_alias.py index f44cf67a1..21370e8cd 100644 --- a/examples/account/account_create_transaction_create_with_alias.py +++ b/examples/account/account_create_transaction_create_with_alias.py @@ -23,6 +23,7 @@ Client, PrivateKey, AccountCreateTransaction, + AccountInfo, AccountInfoQuery, Network, AccountId, @@ -124,7 +125,7 @@ def create_account_with_ecdsa_alias( return new_account_id -def fetch_account_info(client: Client, account_id: AccountId): +def fetch_account_info(client: Client, account_id: AccountId) -> AccountInfo: """Fetch account information from the network. Args: @@ -132,9 +133,9 @@ def fetch_account_info(client: Client, account_id: AccountId): account_id: The account ID to query. Returns: - The account info object. + AccountInfo: The account info object. """ - print("STEP 3: Fetching account information...") + print("\nSTEP 3: Fetching account information...") account_info = ( AccountInfoQuery() .set_account_id(account_id) @@ -143,7 +144,7 @@ def fetch_account_info(client: Client, account_id: AccountId): return account_info -def print_account_summary(account_info) -> None: +def print_account_summary(account_info: AccountInfo) -> None: """Print a summary of the account information. Args: From 94dd9f6765cdd4121238178f2101b6064718f794 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 10 Dec 2025 23:07:45 +0530 Subject: [PATCH 3/3] Update CHANGELOG.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Aditya --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b1363fbc..4c1dc8528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1. - 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) - Modularized `transfer_transaction_fungible` example by introducing `account_balance_query()` & `transfer_transaction()`.Renamed `transfer_tokens()` → `main()` -- 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. +- 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. - Added `__str__()` to CustomFixedFee and updated examples and tests accordingly. - Added unit tests for `crypto_utils` (#993) - Added a github template for good first issues