From 150dd2630e881eedb614db269585971329513539 Mon Sep 17 00:00:00 2001 From: exploreriii <133720349+exploreriii@users.noreply.github.com> Date: Sun, 8 Dec 2024 01:04:56 +0000 Subject: [PATCH] TokenDeleteTransaction TokenDeleteTransaction token_delete.py token_delete_transaction.py test_token_delete_transaction.py test.py account_id naming in unit test readme delete token typo successful hardcoding to env file token_id string token_id readme admin_key integration admin_key token_create_transaction admin_key signing example admin_key test.py creating token readme/example with admin key test enable solo key basic types bytes defining bytes in private key sign admin as is set typo admin_key generate distinct public key test call admin_public_key_bytes test admin_key signing admin_key private public user-friendly and docs transaction body layer Documentation admin key paths uv lock path admin key sign client --- README.md | 21 ++++- examples/token_create.py | 8 +- examples/token_delete.py | 48 ++++++++++ src/hedera_sdk_python/crypto/private_key.py | 15 +++ .../tokens/token_create_transaction.py | 22 ++++- .../tokens/token_delete_transaction.py | 93 +++++++++++++++++++ test.py | 39 +++++++- tests/conftest.py | 4 +- tests/test_token_create_transaction.py | 85 ++++++++++++++++- tests/test_token_delete_transaction.py | 79 ++++++++++++++++ uv.lock | 2 +- 11 files changed, 400 insertions(+), 16 deletions(-) create mode 100644 examples/token_delete.py create mode 100644 src/hedera_sdk_python/tokens/token_delete_transaction.py create mode 100644 tests/test_token_delete_transaction.py diff --git a/README.md b/README.md index 4f929f5..70271b3 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ submitting messages. - [Creating a Token](#creating-a-token) - [Associating a Token](#associating-a-token) - [Transferring Tokens](#transferring-tokens) + - [Deleting a Token](#deleting-a-token) - [Transferring HBAR](#transferring-hbar) - [Creating a Topic](#creating-a-topic) - [Contributing](#contributing) @@ -66,6 +67,7 @@ Create a .env file in the root of your project with the following (replace with ``` OPERATOR_ID=0.0.1234xx OPERATOR_KEY=302e020100300506032b657004220420... +ADMIN_KEY=302a300506032b65700321009308ecfdf... RECIPIENT_ID=0.0.789xx TOKEN_ID=0.0.100xx NETWORK=testnet @@ -96,11 +98,12 @@ New Account Public Key: 8f444e36e8926def492adxxx... Token creation successful. Token ID: 0.0.5025xxx Token association successful. Token transfer successful. +Token deletion successful. ``` ## Usage -Below are examples of how to use the SDK for creating tokens, associating them with accounts, and transferring tokens (also see 'examples' directiory) +Below are examples of how to use the SDK for creating tokens, associating them with accounts, and transferring or deleting tokens (also see 'examples' directiory) ### Creating an Account @@ -127,9 +130,11 @@ transaction = ( .set_decimals(2) .set_initial_supply(1000) .set_treasury_account_id(operator_id) + .set_admin_key(admin_key) # Optional to create a token. Necessary for Token Delete or Update. .freeze_with(client) ) + transaction.sign(admin_key) # If admin key exists. transaction.sign(operator_key) transaction.execute(client) ``` @@ -162,6 +167,20 @@ transaction = ( transaction.execute(client) ``` +### Deleting a Token + +``` + transaction = ( + TokenDeleteTransaction() + .set_token_id(token_id) + .freeze_with(client) + ) + + transaction.sign(admin_key) #Admin key must also have been set in Token Create + transaction.sign(operator_key) + transaction.execute(client) +``` + ### Transfering a HBAR ``` diff --git a/examples/token_create.py b/examples/token_create.py index 129e90d..8ef84ef 100644 --- a/examples/token_create.py +++ b/examples/token_create.py @@ -10,6 +10,7 @@ from hedera_sdk_python.crypto.private_key import PrivateKey from hedera_sdk_python.tokens.token_create_transaction import TokenCreateTransaction from hedera_sdk_python.client.network import Network +from cryptography.hazmat.primitives import serialization load_dotenv() @@ -19,7 +20,8 @@ def create_token(): operator_id = AccountId.from_string(os.getenv('OPERATOR_ID')) operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY')) - + admin_key = PrivateKey.from_string(os.getenv('ADMIN_KEY')) + client.set_operator(operator_id, operator_key) transaction = ( @@ -29,10 +31,12 @@ def create_token(): .set_decimals(2) .set_initial_supply(10) .set_treasury_account_id(operator_id) + .set_admin_key(admin_key) .freeze_with(client) .sign(operator_key) + .sign(admin_key) ) - + try: receipt = transaction.execute(client) if receipt and receipt.tokenId: diff --git a/examples/token_delete.py b/examples/token_delete.py new file mode 100644 index 0000000..f407483 --- /dev/null +++ b/examples/token_delete.py @@ -0,0 +1,48 @@ +import os +import sys +from dotenv import load_dotenv + +project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) +sys.path.insert(0, project_root) + +from hedera_sdk_python.client.client import Client +from hedera_sdk_python.account.account_id import AccountId +from hedera_sdk_python.crypto.private_key import PrivateKey +from hedera_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction +from hedera_sdk_python.client.network import Network +from hedera_sdk_python.tokens.token_id import TokenId + +load_dotenv() + +def delete_token(): + network = Network(network='testnet') + client = Client(network) + + operator_id = AccountId.from_string(os.getenv('OPERATOR_ID')) + operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY')) + admin_key = PrivateKey.from_string(os.getenv('ADMIN_KEY')) + token_id = TokenId.from_string(os.getenv('TOKEN_ID')) + + client.set_operator(operator_id, operator_key) + + transaction = ( + TokenDeleteTransaction() + .set_token_id(token_id) + .freeze_with(client) + .sign(operator_key) + .sign(admin_key) + ) + + try: + receipt = transaction.execute(client) + if receipt is not None and receipt.status == 'SUCCESS': + print(f"Token deletion successful") + else: + print(f"Token deletion failed.") + sys.exit(1) + except Exception as e: + print(f"Token deletion failed: {str(e)}") + sys.exit(1) + +if __name__ == "__main__": + delete_token() \ No newline at end of file diff --git a/src/hedera_sdk_python/crypto/private_key.py b/src/hedera_sdk_python/crypto/private_key.py index 8f6405b..43b79c5 100644 --- a/src/hedera_sdk_python/crypto/private_key.py +++ b/src/hedera_sdk_python/crypto/private_key.py @@ -76,3 +76,18 @@ def to_string(self): encryption_algorithm=serialization.NoEncryption() ) return private_bytes.hex() + + + def to_bytes(self): + """ + Returns the private key as bytes. + + Returns: + bytes: The private key. + """ + private_bytes = self._private_key.private_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PrivateFormat.Raw, + encryption_algorithm=serialization.NoEncryption() + ) + return private_bytes diff --git a/src/hedera_sdk_python/tokens/token_create_transaction.py b/src/hedera_sdk_python/tokens/token_create_transaction.py index d1d3be8..676599e 100644 --- a/src/hedera_sdk_python/tokens/token_create_transaction.py +++ b/src/hedera_sdk_python/tokens/token_create_transaction.py @@ -1,6 +1,7 @@ from hedera_sdk_python.transaction.transaction import Transaction -from hedera_sdk_python.hapi import token_create_pb2 +from hedera_sdk_python.hapi import token_create_pb2, basic_types_pb2 from hedera_sdk_python.response_code import ResponseCode +from cryptography.hazmat.primitives import serialization class TokenCreateTransaction(Transaction): """ @@ -23,6 +24,7 @@ def __init__(self): self.decimals = None self.initial_supply = None self.treasury_account_id = None + self.admin_key = None self._default_transaction_fee = 3_000_000_000 @@ -50,7 +52,12 @@ def set_treasury_account_id(self, account_id): self._require_not_frozen() self.treasury_account_id = account_id return self - + + def set_admin_key(self, admin_key): + self._require_not_frozen() + self.admin_key = admin_key + return self + def build_transaction_body(self): """ Builds and returns the protobuf transaction body for token creation. @@ -70,12 +77,21 @@ def build_transaction_body(self): ]): raise ValueError("Missing required fields") + admin_key_proto = None + if self.admin_key: + admin_public_key_bytes = self.admin_key.public_key().public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + admin_key_proto = basic_types_pb2.Key(ed25519=admin_public_key_bytes) + token_create_body = token_create_pb2.TokenCreateTransactionBody( name=self.token_name, symbol=self.token_symbol, decimals=self.decimals, initialSupply=self.initial_supply, - treasury=self.treasury_account_id.to_proto() + treasury=self.treasury_account_id.to_proto(), + adminKey=admin_key_proto ) transaction_body = self.build_base_transaction_body() diff --git a/src/hedera_sdk_python/tokens/token_delete_transaction.py b/src/hedera_sdk_python/tokens/token_delete_transaction.py new file mode 100644 index 0000000..83a5cb7 --- /dev/null +++ b/src/hedera_sdk_python/tokens/token_delete_transaction.py @@ -0,0 +1,93 @@ +from hedera_sdk_python.transaction.transaction import Transaction +from hedera_sdk_python.hapi import token_delete_pb2 +from hedera_sdk_python.response_code import ResponseCode + +class TokenDeleteTransaction(Transaction): + """ + Represents a token deletion transaction on the Hedera network. + + This transaction deletes a specified token, rendering it inactive. + + Inherits from the base Transaction class and implements the required methods + to build and execute a token deletion transaction. + + """ + + def __init__(self): + """ + Initializes a new TokenDeleteTransaction instance with default values. + """ + super().__init__() + self.token_id = None + self._default_transaction_fee = 3_000_000_000 + + def set_token_id(self, token_id): + self._require_not_frozen() + self.token_id = token_id + return self + + def build_transaction_body(self): + """ + Builds and returns the protobuf transaction body for token deletion. + + Returns: + TransactionBody: The protobuf transaction body containing the token deletion details. + + Raises: + ValueError: If the token ID is missing. + """ + if not self.token_id: + raise ValueError("Missing required TokenID.") + + token_delete_body = token_delete_pb2.TokenDeleteTransactionBody( + token=self.token_id.to_proto() + ) + + transaction_body = self.build_base_transaction_body() + transaction_body.tokenDeletion.CopyFrom(token_delete_body) + + return transaction_body + + def _execute_transaction(self, client, transaction_proto): + """ + Executes the token deletion transaction using the provided client. + + Args: + client (Client): The client instance to use for execution. + transaction_proto (Transaction): The protobuf Transaction message. + + Returns: + TransactionReceipt: The receipt from the network after transaction execution. + + Raises: + Exception: If the transaction submission fails or receives an error response. + """ + response = client.token_stub.deleteToken(transaction_proto) + + if response.nodeTransactionPrecheckCode != ResponseCode.OK: + error_code = response.nodeTransactionPrecheckCode + error_message = ResponseCode.get_name(error_code) + raise Exception(f"Error during transaction submission: {error_code} ({error_message})") + + receipt = self.get_receipt(client) + return receipt + + def get_receipt(self, client, timeout=60): + """ + Retrieves the receipt for the transaction. + + Args: + client (Client): The client instance. + timeout (int): Maximum time in seconds to wait for the receipt. + + Returns: + TransactionReceipt: The transaction receipt from the network. + + Raises: + Exception: If the transaction ID is not set or if receipt retrieval fails. + """ + if self.transaction_id is None: + raise Exception("Transaction ID is not set.") + + receipt = client.get_transaction_receipt(self.transaction_id, timeout) + return receipt diff --git a/test.py b/test.py index 88a3a4d..8bff8f9 100644 --- a/test.py +++ b/test.py @@ -6,11 +6,14 @@ from hedera_sdk_python.account.account_id import AccountId from hedera_sdk_python.account.account_create_transaction import AccountCreateTransaction from hedera_sdk_python.crypto.private_key import PrivateKey +from hedera_sdk_python.crypto.public_key import PublicKey from hedera_sdk_python.tokens.token_create_transaction import TokenCreateTransaction from hedera_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction from hedera_sdk_python.transaction.transfer_transaction import TransferTransaction from hedera_sdk_python.response_code import ResponseCode from hedera_sdk_python.consensus.topic_create_transaction import TopicCreateTransaction +from hedera_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction +from cryptography.hazmat.primitives import serialization load_dotenv() @@ -55,7 +58,7 @@ def create_new_account(client, initial_balance=100000000): return new_account_id, new_account_private_key -def create_token(client, operator_id): +def create_token(client, operator_id, admin_key): """Create a new token and return its TokenId instance.""" transaction = ( @@ -65,10 +68,12 @@ def create_token(client, operator_id): .set_decimals(2) .set_initial_supply(1000) .set_treasury_account_id(operator_id) + .set_admin_key(admin_key) .freeze_with(client) ) - transaction.sign(client.operator_private_key) + transaction.sign(admin_key) + try: receipt = transaction.execute(client) @@ -151,8 +156,35 @@ def create_topic(client): return topic_id +def delete_token(client, token_id, admin_key): + """Deletes the specified token on the Hedera network.""" + transaction = ( + TokenDeleteTransaction() + .set_token_id(token_id) + .freeze_with(client) + ) + + transaction.sign(client.operator_private_key) + transaction.sign(admin_key) + + try: + receipt = transaction.execute(client) + if receipt.status != ResponseCode.SUCCESS: + status_message = ResponseCode.get_name(receipt.status) + raise Exception(f"Token deletion failed with status: {status_message}") + print("Token deletion successful.") + except Exception as e: + print(f"Token deletion failed: {str(e)}") + sys.exit(1) + def main(): operator_id, operator_key = load_operator_credentials() + admin_key = PrivateKey.generate() + admin_public_key = admin_key.public_key() + admin_public_key_bytes = admin_public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) network_type = os.getenv('NETWORK') network = Network(network=network_type) @@ -161,9 +193,10 @@ def main(): client.set_operator(operator_id, operator_key) recipient_id, recipient_private_key = create_new_account(client) - token_id = create_token(client, operator_id) + token_id = create_token(client, operator_id, admin_key) associate_token(client, recipient_id, recipient_private_key, token_id) transfer_token(client, recipient_id, token_id) + delete_token(client, token_id, admin_key) topic_id = create_topic(client) diff --git a/tests/conftest.py b/tests/conftest.py index fbce6b7..79e9368 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,8 @@ import pytest from hedera_sdk_python.account.account_id import AccountId from hedera_sdk_python.tokens.token_id import TokenId +from hedera_sdk_python.crypto.private_key import PrivateKey +from cryptography.hazmat.primitives import serialization @pytest.fixture def mock_account_ids(): @@ -10,4 +12,4 @@ def mock_account_ids(): node_account_id = AccountId(0, 0, 3) token_id_1 = TokenId(1, 1, 1) token_id_2 = TokenId(2, 2, 2) - return account_id_sender, account_id_recipient, node_account_id, token_id_1, token_id_2 + return account_id_sender, account_id_recipient, node_account_id, token_id_1, token_id_2 \ No newline at end of file diff --git a/tests/test_token_create_transaction.py b/tests/test_token_create_transaction.py index 517f280..ec8e39a 100644 --- a/tests/test_token_create_transaction.py +++ b/tests/test_token_create_transaction.py @@ -1,8 +1,9 @@ import pytest from unittest.mock import MagicMock from hedera_sdk_python.tokens.token_create_transaction import TokenCreateTransaction -from hedera_sdk_python.hapi import basic_types_pb2, timestamp_pb2 +from hedera_sdk_python.hapi import basic_types_pb2, timestamp_pb2, transaction_pb2, transaction_body_pb2 from hedera_sdk_python.transaction.transaction_id import TransactionId +from cryptography.hazmat.primitives import serialization def generate_transaction_id(account_id_proto): """Generate a unique transaction ID based on the account ID and the current timestamp.""" @@ -19,10 +20,35 @@ def generate_transaction_id(account_id_proto): ) return tx_id +def test_build_transaction_body_without_admin_key(mock_account_ids): + """Test building a token creation transaction body without an admin key.""" + treasury_account, _, node_account_id, _, _ = mock_account_ids + + token_tx = TokenCreateTransaction() + token_tx.set_token_name("MyToken") + token_tx.set_token_symbol("MTK") + token_tx.set_decimals(2) + token_tx.set_initial_supply(1000) + token_tx.set_treasury_account_id(treasury_account) + token_tx.transaction_id = generate_transaction_id(treasury_account) + token_tx.node_account_id = node_account_id + + transaction_body = token_tx.build_transaction_body() + + assert transaction_body.tokenCreation.name == "MyToken" + assert transaction_body.tokenCreation.symbol == "MTK" + assert transaction_body.tokenCreation.decimals == 2 + assert transaction_body.tokenCreation.initialSupply == 1000 + assert not transaction_body.tokenCreation.HasField("adminKey") + def test_build_transaction_body(mock_account_ids): """Test building a token creation transaction body with valid values.""" treasury_account, _, node_account_id, _, _ = mock_account_ids + private_key_admin = MagicMock() + private_key_admin.sign.return_value = b'admin_signature' + private_key_admin.public_key().public_bytes.return_value = b'admin_public_key' + token_tx = TokenCreateTransaction() token_tx.set_token_name("MyToken") token_tx.set_token_symbol("MTK") @@ -30,6 +56,7 @@ def test_build_transaction_body(mock_account_ids): token_tx.set_initial_supply(1000) token_tx.set_treasury_account_id(treasury_account) token_tx.transaction_id = generate_transaction_id(treasury_account) + token_tx.set_admin_key(private_key_admin) token_tx.node_account_id = node_account_id transaction_body = token_tx.build_transaction_body() @@ -38,6 +65,7 @@ def test_build_transaction_body(mock_account_ids): assert transaction_body.tokenCreation.symbol == "MTK" assert transaction_body.tokenCreation.decimals == 2 assert transaction_body.tokenCreation.initialSupply == 1000 + assert transaction_body.tokenCreation.adminKey.ed25519 == b'admin_public_key' def test_missing_fields(): """Test that building a transaction without required fields raises a ValueError.""" @@ -48,6 +76,7 @@ def test_missing_fields(): def test_sign_transaction(mock_account_ids): """Test signing the token creation transaction with a private key.""" treasury_account, _, node_account_id, _, _ = mock_account_ids + token_tx = TokenCreateTransaction() token_tx.set_token_name("MyToken") token_tx.set_token_symbol("MTK") @@ -61,17 +90,27 @@ def test_sign_transaction(mock_account_ids): private_key.sign.return_value = b'signature' private_key.public_key().public_bytes.return_value = b'public_key' + private_key_admin = MagicMock() + private_key_admin.sign.return_value = b'admin_signature' + private_key_admin.public_key().public_bytes.return_value = b'admin_public_key' + token_tx.sign(private_key) + token_tx.sign(private_key_admin) + + assert len(token_tx.signature_map.sigPair) == 2 - assert len(token_tx.signature_map.sigPair) == 1 sig_pair = token_tx.signature_map.sigPair[0] assert sig_pair.pubKeyPrefix == b'public_key' assert sig_pair.ed25519 == b'signature' + sig_pair_admin = token_tx.signature_map.sigPair[1] + assert sig_pair_admin.pubKeyPrefix == b'admin_public_key' + assert sig_pair_admin.ed25519 == b'admin_signature' -def test_to_proto(mock_account_ids): - """Test converting the token creation transaction to protobuf format after signing.""" +def test_to_proto_without_admin_key(mock_account_ids): + """Test protobuf conversion when admin key is not set.""" treasury_account, _, node_account_id, _, _ = mock_account_ids + token_tx = TokenCreateTransaction() token_tx.set_token_name("MyToken") token_tx.set_token_symbol("MTK") @@ -88,5 +127,41 @@ def test_to_proto(mock_account_ids): token_tx.sign(private_key) proto = token_tx.to_proto() - assert proto.signedTransactionBytes assert len(proto.signedTransactionBytes) > 0 + + transaction = transaction_pb2.Transaction.FromString(proto.signedTransactionBytes) + transaction_body = transaction_body_pb2.TransactionBody.FromString(transaction.bodyBytes) + + assert not transaction_body.tokenCreation.HasField("adminKey") + +def test_to_proto(mock_account_ids): + """Test converting the token creation transaction to protobuf format after signing.""" + treasury_account, _, node_account_id, _, _ = mock_account_ids + + private_key = MagicMock() + private_key.sign.return_value = b'signature' + private_key.public_key().public_bytes.return_value = b'public_key' + + private_key_admin = MagicMock() + private_key_admin.sign.return_value = b'admin_signature' + private_key_admin.public_key().public_bytes.return_value = b'admin_public_key' + + token_tx = TokenCreateTransaction() + token_tx.set_token_name("MyToken") + token_tx.set_token_symbol("MTK") + token_tx.set_decimals(2) + token_tx.set_initial_supply(1000) + token_tx.set_treasury_account_id(treasury_account) + token_tx.set_admin_key(private_key_admin) + token_tx.transaction_id = generate_transaction_id(treasury_account) + token_tx.node_account_id = node_account_id + + token_tx.sign(private_key) + token_tx.sign(private_key_admin) + proto = token_tx.to_proto() + + assert len(proto.signedTransactionBytes) > 0 + + transaction = transaction_pb2.Transaction.FromString(proto.signedTransactionBytes) + + assert transaction.body.tokenCreation.adminKey.ed25519 == b'admin_public_key' diff --git a/tests/test_token_delete_transaction.py b/tests/test_token_delete_transaction.py new file mode 100644 index 0000000..b92c4e7 --- /dev/null +++ b/tests/test_token_delete_transaction.py @@ -0,0 +1,79 @@ +import pytest +from unittest.mock import MagicMock +from hedera_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction +from hedera_sdk_python.hapi import basic_types_pb2, timestamp_pb2 +from hedera_sdk_python.transaction.transaction_id import TransactionId + +def generate_transaction_id(account_id_proto): + """Generate a unique transaction ID based on the account ID and the current timestamp.""" + import time + current_time = time.time() + timestamp_seconds = int(current_time) + timestamp_nanos = int((current_time - timestamp_seconds) * 1e9) + + tx_timestamp = timestamp_pb2.Timestamp(seconds=timestamp_seconds, nanos=timestamp_nanos) + + tx_id = TransactionId( + valid_start=tx_timestamp, + account_id=account_id_proto + ) + return tx_id + +def test_build_transaction_body(mock_account_ids): + """Test building a token delete transaction body with a valid value.""" + account_id, _, node_account_id, token_id, _= mock_account_ids + + delete_tx = TokenDeleteTransaction() + delete_tx.set_token_id(token_id) + delete_tx.transaction_id = generate_transaction_id(account_id) + delete_tx.node_account_id = node_account_id + + transaction_body = delete_tx.build_transaction_body() + + assert transaction_body.tokenDeletion.token.shardNum == 1 + assert transaction_body.tokenDeletion.token.realmNum == 1 + assert transaction_body.tokenDeletion.token.tokenNum == 1 + +def test_missing_token_id(): + """Test that building a transaction without setting TokenID raises a ValueError.""" + delete_tx = TokenDeleteTransaction() + with pytest.raises(ValueError, match="Missing required TokenID."): + delete_tx.build_transaction_body() + +def test_sign_transaction(mock_account_ids): + """Test signing the token delete transaction with a private key.""" + operator_id, _, node_account_id, token_id, _= mock_account_ids + delete_tx = TokenDeleteTransaction() + delete_tx.set_token_id(token_id) + delete_tx.transaction_id = generate_transaction_id(operator_id) + delete_tx.node_account_id = node_account_id + + private_key = MagicMock() + private_key.sign.return_value = b'signature' + private_key.public_key().public_bytes.return_value = b'public_key' + + delete_tx.sign(private_key) + + assert len(delete_tx.signature_map.sigPair) == 1 + sig_pair = delete_tx.signature_map.sigPair[0] + assert sig_pair.pubKeyPrefix == b'public_key' + assert sig_pair.ed25519 == b'signature' + + +def test_to_proto(mock_account_ids): + """Test converting the token delete transaction to protobuf format after signing.""" + operator_id, _, node_account_id, token_id, _= mock_account_ids + delete_tx = TokenDeleteTransaction() + delete_tx.set_token_id(token_id) + delete_tx.transaction_id = generate_transaction_id(operator_id) + delete_tx.node_account_id = node_account_id + + private_key = MagicMock() + private_key.sign.return_value = b'signature' + private_key.public_key().public_bytes.return_value = b'public_key' + + delete_tx.sign(private_key) + proto = delete_tx.to_proto() + + assert proto.signedTransactionBytes + assert len(proto.signedTransactionBytes) > 0 diff --git a/uv.lock b/uv.lock index db93e76..e80cdf8 100644 --- a/uv.lock +++ b/uv.lock @@ -331,7 +331,7 @@ wheels = [ [[package]] name = "hedera-sdk-python" -version = "0.1.dev84+ge8dc25f.d20241220" +version = "0.1.dev119+gbb0268d.d20241228" source = { editable = "." } dependencies = [ { name = "cryptography" },