From 61ee06a45eb082857e1aca39227323e0a7439436 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Thu, 20 Nov 2025 01:08:58 +0530 Subject: [PATCH 1/8] chore: prepare for rebase Signed-off-by: undefinedIsMyLife --- .../token_create_transaction_pause_key.py | 319 ++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 examples/token_create_transaction_pause_key.py diff --git a/examples/token_create_transaction_pause_key.py b/examples/token_create_transaction_pause_key.py new file mode 100644 index 000000000..4e5413102 --- /dev/null +++ b/examples/token_create_transaction_pause_key.py @@ -0,0 +1,319 @@ +""" +This example demonstrates the pause key capabilities for token management using the Hiero Python SDK. + +It shows: +1. Creating a token *without* a pause key +2. Attempting to pause it — expected failure +3. Creating a token *with* a pause key +4. Successfully pausing and unpausing the token +5. Demonstrating that transfers fail while the token is paused +6. (Bonus) Removing the pause key while the token is paused → permanently paused + +Required environment variables: +- OPERATOR_ID +- OPERATOR_KEY + +Usage: +uv run examples/token_create_transaction_pause_key.py +""" + +import os +import sys +from dotenv import load_dotenv + +from hiero_sdk_python import ( + Client, + AccountId, + PrivateKey, + Network, + TokenCreateTransaction, + TokenPauseTransaction, + TokenUnpauseTransaction, + TokenUpdateTransaction, + TokenInfoQuery, + TransferTransaction, + AccountCreateTransaction, + Hbar, +) + +from hiero_sdk_python.response_code import ResponseCode +from hiero_sdk_python.tokens.token_type import TokenType +from hiero_sdk_python.tokens.supply_type import SupplyType + +load_dotenv() +network_name = os.getenv("NETWORK", "testnet").lower() + + +# ------------------------------------------------------- +# CLIENT SETUP +# ------------------------------------------------------- +def setup_client(): + """Create client from environment variables""" + network = Network(network_name) + print(f"Connecting to Hedera {network_name} network...") + client = Client(network) + + try: + operator_id = AccountId.from_string(os.getenv("OPERATOR_ID", "")) + operator_key = PrivateKey.from_string(os.getenv("OPERATOR_KEY", "")) + client.set_operator(operator_id, operator_key) + print(f"Client ready — Operator: {client.operator_account_id}\n") + return client, operator_id, operator_key + + except Exception: + print("āŒ ERROR: Invalid OPERATOR_ID or OPERATOR_KEY in .env") + sys.exit(1) + + +# ------------------------------------------------------- +# TOKEN CREATION (NO PAUSE KEY) +# ------------------------------------------------------- +def create_token_without_pause_key(client, operator_id, operator_key): + print("šŸ”¹ Creating token WITHOUT pause key...") + + tx = ( + TokenCreateTransaction() + .set_token_name("PauseKeyMissing") + .set_token_symbol("NOPAUSE") + .set_decimals(0) + .set_initial_supply(100) + .set_treasury_account_id(operator_id) + .set_token_type(TokenType.FUNGIBLE_COMMON) + .set_supply_type(SupplyType.INFINITE) + .freeze_with(client) + .sign(operator_key) + ) + + receipt = tx.execute(client) + if receipt.status != ResponseCode.SUCCESS: + print("āŒ Token creation failed") + sys.exit(1) + + token_id = receipt.token_id + print(f"āœ… Token created WITHOUT pause key → {token_id}\n") + return token_id + + +def attempt_pause_should_fail(client, token_id, operator_key): + print("šŸ”¹ Attempting to pause token WITHOUT a pause key... (expected failure)") + try: + tx = ( + TokenPauseTransaction() + .set_token_id(token_id) + .freeze_with(client) + .sign(operator_key) + ) + receipt = tx.execute(client) + + print("āš ļø Unexpected success! Pause should NOT be possible.") + print(f"Status: {ResponseCode(receipt.status).name}\n") + + except Exception as e: + print(f"āœ… Expected failure occurred: {e}\n") + + +# ------------------------------------------------------- +# TOKEN CREATION WITH PAUSE KEY +# ------------------------------------------------------- +def create_token_with_pause_key(client, operator_id, operator_key, pause_key): + print("šŸ”¹ Creating token WITH pause key...") + + tx = ( + TokenCreateTransaction() + .set_token_name("PauseKeyDemo") + .set_token_symbol("PAUSE") + .set_decimals(0) + .set_initial_supply(100) + .set_treasury_account_id(operator_id) + .set_token_type(TokenType.FUNGIBLE_COMMON) + .set_supply_type(SupplyType.INFINITE) + .set_pause_key(pause_key) # NEW + .freeze_with(client) + ) + + tx.sign(operator_key) + tx.sign(pause_key) + + receipt = tx.execute(client) + if receipt.status != ResponseCode.SUCCESS: + print("āŒ Token creation failed") + sys.exit(1) + + token_id = receipt.token_id + print(f"āœ… Token created WITH pause key → {token_id}\n") + return token_id + + +# ------------------------------------------------------- +# PAUSE / UNPAUSE DEMO +# ------------------------------------------------------- +def pause_token(client, token_id, pause_key): + print("šŸ”¹ Pausing token...") + + tx = ( + TokenPauseTransaction() + .set_token_id(token_id) + .freeze_with(client) + .sign(pause_key) + ) + + receipt = tx.execute(client) + if receipt.status == ResponseCode.SUCCESS: + print("āœ… Token paused successfully!\n") + else: + print(f"āŒ Pause failed: {ResponseCode(receipt.status).name}") + + +def unpause_token(client, token_id, pause_key): + print("šŸ”¹ Unpausing token...") + + tx = ( + TokenUnpauseTransaction() + .set_token_id(token_id) + .freeze_with(client) + .sign(pause_key) + ) + + receipt = tx.execute(client) + if receipt.status == ResponseCode.SUCCESS: + print("āœ… Token unpaused successfully!\n") + else: + print(f"āŒ Unpause failed: {ResponseCode(receipt.status).name}") + + +# ------------------------------------------------------- +# TRANSFERS WHILE PAUSED SHOULD FAIL +# ------------------------------------------------------- +def create_temp_account(client, operator_key): + """Creates a small account for transfer testing.""" + new_key = PrivateKey.generate_ed25519() + pub_key = new_key.public_key() + + print("šŸ”¹ Creating a temporary recipient account...") + + tx = ( + AccountCreateTransaction() + .set_key(pub_key) # MUST use public key + .set_initial_balance(Hbar.from_tinybars(1000)) + .freeze_with(client) + .sign(operator_key) + ) + + receipt = tx.execute(client) + account_id = receipt.account_id + print(f"āœ… Temp account created: {account_id}\n") + return account_id, new_key + + + +def test_transfer_while_paused(client, operator_id, operator_key, recipient_id, token_id): + print("šŸ”¹ Attempting transfer WHILE token is paused (expected failure)...") + + tx = ( + TransferTransaction() + .add_token_transfer(token_id, operator_id, -10) + .add_token_transfer(token_id, recipient_id, 10) + .freeze_with(client) + .sign(operator_key) + ) + + receipt = tx.execute(client) + + if receipt.status == ResponseCode.TOKEN_IS_PAUSED: + print("āœ… Transfer failed as expected: TOKEN_IS_PAUSED\n") + else: + print(f"āš ļø Unexpected status: {ResponseCode(receipt.status).name}\n") + + + +# ------------------------------------------------------- +# BONUS: REMOVE PAUSE KEY WHILE PAUSED → PERMANENT +# ------------------------------------------------------- +def remove_pause_key(client, token_id, pause_key): + print("šŸ”¹ Removing pause key while token is UNPAUSED...") + + tx = ( + TokenUpdateTransaction() + .set_token_id(token_id) + .set_pause_key(None) + .freeze_with(client) + .sign(pause_key) + ) + + receipt = tx.execute(client) + + if receipt.status == ResponseCode.SUCCESS: + print("āœ… Pause key removed successfully.\n") + return True + else: + print(f"āŒ Failed to remove pause key: {ResponseCode(receipt.status).name}\n") + return False + + +def attempt_unpause_after_removal_should_fail(client, token_id): + print("šŸ”¹ Attempting to unpause a token with NO pause key (should fail)...") + + try: + tx = ( + TokenUnpauseTransaction() + .set_token_id(token_id) + .freeze_with(client) + ) + + # Do NOT sign — because pause key no longer exists + receipt = tx.execute(client) + + print(f"āš ļø Unexpected status: {ResponseCode(receipt.status).name}\n") + + except Exception as e: + print(f"āœ… Permanent unpause failure occurred as expected: {e}\n") + + + +# ------------------------------------------------------- +# MAIN +# ------------------------------------------------------- +def main(): + client, operator_id, operator_key = setup_client() + + print("\n==================== PART 1 — NO PAUSE KEY ====================\n") + token_no_pause = create_token_without_pause_key(client, operator_id, operator_key) + attempt_pause_should_fail(client, token_no_pause, operator_key) + + print("\n==================== PART 2 — WITH PAUSE KEY ====================\n") + pause_key = PrivateKey.generate_ed25519() + + token_with_pause = create_token_with_pause_key( + client, operator_id, operator_key, pause_key + ) + + pause_token(client, token_with_pause, pause_key) + + recipient_id, _ = create_temp_account(client, operator_key) + test_transfer_while_paused( + client, operator_id, operator_key, recipient_id, token_with_pause + ) + + unpause_token(client, token_with_pause, pause_key) + + print("\n==================== BONUS — PERMANENT PAUSE ====================\n") + # 1. Pause + pause_token(client, token_with_pause, pause_key) + + # 2. Unpause (required to modify keys) + unpause_token(client, token_with_pause, pause_key) + + # 3. Remove pause key + if remove_pause_key(client, token_with_pause, pause_key): + + # 4. Pause again + pause_token(client, token_with_pause, pause_key) + + # 5. Unpause should now fail permanently + attempt_unpause_after_removal_should_fail(client, token_with_pause) + +print("\nšŸŽ‰ Pause key demonstration completed!") + + +if __name__ == "__main__": + main() From 573a36fe0c4a49086585416e2d342a5f0e28f380 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Sun, 23 Nov 2025 23:44:29 +0530 Subject: [PATCH 2/8] fix(example): remove unsupported bonus pause key removal logic Signed-off-by: undefinedIsMyLife --- .../token_create_transaction_pause_key.py | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/examples/token_create_transaction_pause_key.py b/examples/token_create_transaction_pause_key.py index 4e5413102..26b18889b 100644 --- a/examples/token_create_transaction_pause_key.py +++ b/examples/token_create_transaction_pause_key.py @@ -224,52 +224,6 @@ def test_transfer_while_paused(client, operator_id, operator_key, recipient_id, else: print(f"āš ļø Unexpected status: {ResponseCode(receipt.status).name}\n") - - -# ------------------------------------------------------- -# BONUS: REMOVE PAUSE KEY WHILE PAUSED → PERMANENT -# ------------------------------------------------------- -def remove_pause_key(client, token_id, pause_key): - print("šŸ”¹ Removing pause key while token is UNPAUSED...") - - tx = ( - TokenUpdateTransaction() - .set_token_id(token_id) - .set_pause_key(None) - .freeze_with(client) - .sign(pause_key) - ) - - receipt = tx.execute(client) - - if receipt.status == ResponseCode.SUCCESS: - print("āœ… Pause key removed successfully.\n") - return True - else: - print(f"āŒ Failed to remove pause key: {ResponseCode(receipt.status).name}\n") - return False - - -def attempt_unpause_after_removal_should_fail(client, token_id): - print("šŸ”¹ Attempting to unpause a token with NO pause key (should fail)...") - - try: - tx = ( - TokenUnpauseTransaction() - .set_token_id(token_id) - .freeze_with(client) - ) - - # Do NOT sign — because pause key no longer exists - receipt = tx.execute(client) - - print(f"āš ļø Unexpected status: {ResponseCode(receipt.status).name}\n") - - except Exception as e: - print(f"āœ… Permanent unpause failure occurred as expected: {e}\n") - - - # ------------------------------------------------------- # MAIN # ------------------------------------------------------- @@ -296,22 +250,6 @@ def main(): unpause_token(client, token_with_pause, pause_key) - print("\n==================== BONUS — PERMANENT PAUSE ====================\n") - # 1. Pause - pause_token(client, token_with_pause, pause_key) - - # 2. Unpause (required to modify keys) - unpause_token(client, token_with_pause, pause_key) - - # 3. Remove pause key - if remove_pause_key(client, token_with_pause, pause_key): - - # 4. Pause again - pause_token(client, token_with_pause, pause_key) - - # 5. Unpause should now fail permanently - attempt_unpause_after_removal_should_fail(client, token_with_pause) - print("\nšŸŽ‰ Pause key demonstration completed!") From fd43b04eedb8f6ee45628967b9d804022f6d3498 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Mon, 24 Nov 2025 12:18:38 +0530 Subject: [PATCH 3/8] chore(example): remove unsupported bonus pause-key section Signed-off-by: undefinedIsMyLife --- examples/token_create_transaction_pause_key.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/token_create_transaction_pause_key.py b/examples/token_create_transaction_pause_key.py index 26b18889b..1ac21455b 100644 --- a/examples/token_create_transaction_pause_key.py +++ b/examples/token_create_transaction_pause_key.py @@ -7,7 +7,7 @@ 3. Creating a token *with* a pause key 4. Successfully pausing and unpausing the token 5. Demonstrating that transfers fail while the token is paused -6. (Bonus) Removing the pause key while the token is paused → permanently paused + Required environment variables: - OPERATOR_ID From e0fde7ed7b83fe9e365df9de31d47ffd4e7d7dcf Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Mon, 24 Nov 2025 19:58:26 +0530 Subject: [PATCH 4/8] fix(example): improve receipt handling per review feedback Signed-off-by: undefinedIsMyLife --- .../token_create_transaction_pause_key.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/token_create_transaction_pause_key.py b/examples/token_create_transaction_pause_key.py index 1ac21455b..a90f50a5c 100644 --- a/examples/token_create_transaction_pause_key.py +++ b/examples/token_create_transaction_pause_key.py @@ -96,20 +96,20 @@ def create_token_without_pause_key(client, operator_id, operator_key): def attempt_pause_should_fail(client, token_id, operator_key): print("šŸ”¹ Attempting to pause token WITHOUT a pause key... (expected failure)") - try: - tx = ( - TokenPauseTransaction() - .set_token_id(token_id) - .freeze_with(client) - .sign(operator_key) - ) - receipt = tx.execute(client) - print("āš ļø Unexpected success! Pause should NOT be possible.") - print(f"Status: {ResponseCode(receipt.status).name}\n") + tx = ( + TokenPauseTransaction() + .set_token_id(token_id) + .freeze_with(client) + .sign(operator_key) + ) - except Exception as e: - print(f"āœ… Expected failure occurred: {e}\n") + receipt = tx.execute(client) + + if receipt.status == ResponseCode.TOKEN_HAS_NO_PAUSE_KEY: + print("āœ… Expected failure: token cannot be paused because no pause key exists.\n") + else: + print(f"āŒ Unexpected status: {ResponseCode(receipt.status).name}\n") # ------------------------------------------------------- @@ -200,8 +200,14 @@ def create_temp_account(client, operator_key): ) receipt = tx.execute(client) + + if receipt.status != ResponseCode.SUCCESS: + print(f"āŒ Failed to create temp account: {ResponseCode(receipt.status).name}") + sys.exit(1) + account_id = receipt.account_id print(f"āœ… Temp account created: {account_id}\n") + return account_id, new_key From 1e763210e2e4396f4992e836f2f69f08cf6b3327 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Wed, 26 Nov 2025 22:20:08 +0530 Subject: [PATCH 5/8] fix(example): receipt checks and cleanup Signed-off-by: undefinedIsMyLife --- examples/token_create_transaction_pause_key.py | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/token_create_transaction_pause_key.py b/examples/token_create_transaction_pause_key.py index a90f50a5c..ba2c2d485 100644 --- a/examples/token_create_transaction_pause_key.py +++ b/examples/token_create_transaction_pause_key.py @@ -8,7 +8,6 @@ 4. Successfully pausing and unpausing the token 5. Demonstrating that transfers fail while the token is paused - Required environment variables: - OPERATOR_ID - OPERATOR_KEY From a9fb700c75334c4f377e97d67e9af517e33c1425 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Thu, 27 Nov 2025 14:57:26 +0530 Subject: [PATCH 6/8] fix(changelog): restore removed lines and update entry Signed-off-by: undefinedIsMyLife --- examples/{ => tokens}/token_create_transaction_pause_key.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{ => tokens}/token_create_transaction_pause_key.py (100%) diff --git a/examples/token_create_transaction_pause_key.py b/examples/tokens/token_create_transaction_pause_key.py similarity index 100% rename from examples/token_create_transaction_pause_key.py rename to examples/tokens/token_create_transaction_pause_key.py From 374fa70b91b686759529f88be969d33be2c23afa Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Fri, 28 Nov 2025 22:47:41 +0530 Subject: [PATCH 7/8] fix(example): final reviewer adjustments Signed-off-by: undefinedIsMyLife --- examples/tokens/token_create_transaction_pause_key.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tokens/token_create_transaction_pause_key.py b/examples/tokens/token_create_transaction_pause_key.py index ba2c2d485..026040c42 100644 --- a/examples/tokens/token_create_transaction_pause_key.py +++ b/examples/tokens/token_create_transaction_pause_key.py @@ -255,7 +255,7 @@ def main(): unpause_token(client, token_with_pause, pause_key) -print("\nšŸŽ‰ Pause key demonstration completed!") + print("\nšŸŽ‰ Pause key demonstration completed!") if __name__ == "__main__": From 9e791ceda8aa52796dd2227463973a655c7da623 Mon Sep 17 00:00:00 2001 From: undefinedIsMyLife Date: Fri, 28 Nov 2025 23:33:12 +0530 Subject: [PATCH 8/8] fix(changelog): correct path and PR number for pause key example (#833) Signed-off-by: undefinedIsMyLife --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785f601c9..d52f33086 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 +- Add examples/tokens/token_create_transaction_pause_key.py example demonstrating token pause/unpause behavior and pause key usage (#833) - Added docs/sdk_developers/training/setup: a training to set up as a developer to the python sdk - Add example demonstrating usage of `CustomFeeLimit` in `examples/transaction/custom_fee_limit.py` - Added `.github/workflows/merge-conflict-bot.yml` to automatically detect and notify users of merge conflicts in Pull Requests.