Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/hiero_sdk_python/tokens/token_dissociate_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,16 +98,15 @@ def _build_proto_body(self) -> token_dissociate_pb2.TokenDissociateTransactionBo

Returns:
TokenDissociateTransactionBody: The protobuf body for this transaction.

Raises:
ValueError: If account ID or token IDs are not set.
"""
if not self.account_id or not self.token_ids:
raise ValueError("Account ID and token IDs must be set.")
transaction_body = token_dissociate_pb2.TokenDissociateTransactionBody()

if self.account_id is not None:
transaction_body.account.CopyFrom(self.account_id._to_proto())
if self.token_ids is not None:
transaction_body.tokens.extend(token_id._to_proto() for token_id in self.token_ids if token_id is not None)

return token_dissociate_pb2.TokenDissociateTransactionBody(
account=self.account_id._to_proto(), tokens=[token_id._to_proto() for token_id in self.token_ids]
)
return transaction_body

def build_transaction_body(self) -> transaction_pb2.TransactionBody:
"""
Expand Down
90 changes: 59 additions & 31 deletions tests/integration/token_dissociate_transaction_e2e_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,81 @@

from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
from hiero_sdk_python.crypto.private_key import PrivateKey
from hiero_sdk_python.exceptions import PrecheckError
from hiero_sdk_python.hbar import Hbar
from hiero_sdk_python.response_code import ResponseCode
from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction
from hiero_sdk_python.tokens.token_dissociate_transaction import TokenDissociateTransaction
from tests.integration.utils import IntegrationTestEnv, create_fungible_token
from tests.integration.utils import create_fungible_token


def _create_associated_account(env):
"""Creates an account and associates it with a fungible token."""
private_key = PrivateKey.generate()

receipt = (
AccountCreateTransaction()
.set_key_without_alias(private_key)
.set_initial_balance(Hbar(2))
.set_account_memo("Recipient Account")
.freeze_with(env.client)
.execute(env.client)
)

account_id = receipt.account_id
token_id = create_fungible_token(env)

associate_tx = TokenAssociateTransaction().set_account_id(account_id).set_token_ids([token_id])
associate_tx.freeze_with(env.client)
associate_tx.sign(private_key)

receipt = associate_tx.execute(env.client)

assert receipt.status == ResponseCode.SUCCESS, (
f"Token association failed with status: {ResponseCode(receipt.status).name}"
)

return account_id, private_key, token_id


@pytest.mark.integration
def test_integration_token_dissociate_transaction_can_execute():
env = IntegrationTestEnv()
def test_integration_token_dissociate_transaction_can_execute(env):
"""Test token dissociate transaction can be executed successfully."""
account_id, account_private_key, token_id = _create_associated_account(env)

try:
new_account_private_key = PrivateKey.generate()
new_account_public_key = new_account_private_key.public_key()
dissociate_transaction = TokenDissociateTransaction(account_id=account_id, token_ids=[token_id])
dissociate_transaction.freeze_with(env.client)
dissociate_transaction.sign(account_private_key)

initial_balance = Hbar(2)
receipt = dissociate_transaction.execute(env.client)

assert initial_balance.to_tinybars() == 200000000
assert receipt.status == ResponseCode.SUCCESS, (
f"Token dissociation failed with status: {ResponseCode(receipt.status).name}"
)

Comment thread
exploreriii marked this conversation as resolved.
account_transaction = AccountCreateTransaction(
key=new_account_public_key, initial_balance=initial_balance, memo="Recipient Account"
)

account_transaction.freeze_with(env.client)
account_receipt = account_transaction.execute(env.client)
new_account_id = account_receipt.account_id
def test_token_dissociate_transaction_can_execute_with_no_tokensId(env):
"""Test token dissociate transaction can be executed without setting the tokenIds."""
account_id, account_private_key, _ = _create_associated_account(env)

token_id = create_fungible_token(env)
dissociate_transaction = TokenDissociateTransaction(account_id=account_id)
dissociate_transaction.freeze_with(env.client)
dissociate_transaction.sign(account_private_key)

associate_transaction = TokenAssociateTransaction(account_id=new_account_id, token_ids=[token_id])
associate_transaction.freeze_with(env.client)
associate_transaction.sign(new_account_private_key)
receipt = dissociate_transaction.execute(env.client)

receipt = associate_transaction.execute(env.client)
assert receipt.status == ResponseCode.SUCCESS, (
f"Token dissociation failed with status: {ResponseCode(receipt.status).name}"
)

assert receipt.status == ResponseCode.SUCCESS, (
f"Token association failed with status: {ResponseCode(receipt.status).name}"
)

dissociate_transaction = TokenDissociateTransaction(account_id=new_account_id, token_ids=[token_id])
dissociate_transaction.freeze_with(env.client)
dissociate_transaction.sign(new_account_private_key)
def test_token_dissociate_transaction_raise_error_if_account_id_not_set(env):
"""Test token dissociate transaction raises PrecheckError if accountId not set."""
a_, account_private_key, token_id = _create_associated_account(env)

receipt = dissociate_transaction.execute(env.client)
dissociate_transaction = TokenDissociateTransaction(token_ids=[token_id])
dissociate_transaction.freeze_with(env.client)
dissociate_transaction.sign(account_private_key)

assert receipt.status == ResponseCode.SUCCESS, (
f"Token dissociation failed with status: {ResponseCode(receipt.status).name}"
)
finally:
env.close()
with pytest.raises(PrecheckError):
dissociate_transaction.execute(env.client)
Comment thread
exploreriii marked this conversation as resolved.
76 changes: 76 additions & 0 deletions tests/unit/token_dissociate_transaction_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,79 @@ def test_build_scheduled_body(mock_account_ids):
assert len(schedulable_body.tokenDissociate.tokens) == len(token_ids)
for i, token_id in enumerate(token_ids):
assert schedulable_body.tokenDissociate.tokens[i] == token_id._to_proto()


def test_build_protobuf_body(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction."""
account_id, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]

tx = TokenDissociateTransaction().set_account_id(account_id).set_token_ids(token_ids)

body = tx._build_proto_body()

assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()

assert len(body.tokens) == len(token_ids)
assert list(body.tokens) == [token._to_proto() for token in token_ids]


def test_build_protobuf_body_ignore_none_tokens(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction ignores none tokenId in list."""
account_id, _, _, token_id, _ = mock_account_ids
token_ids = [token_id, None]

tx = TokenDissociateTransaction().set_account_id(account_id).set_token_ids(token_ids)

body = tx._build_proto_body()

assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()

assert len(body.tokens) == 1
assert list(body.tokens) == [token_id._to_proto()]


def test_build_protobuf_body_without_account_id(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction without accountId."""
_, _, _, token_id_1, token_id_2 = mock_account_ids
token_ids = [token_id_1, token_id_2]

tx = TokenDissociateTransaction().set_token_ids(token_ids)

body = tx._build_proto_body()

assert body is not None
assert not body.HasField("account")

assert len(body.tokens) == len(token_ids)
assert list(body.tokens) == [token._to_proto() for token in token_ids]


def test_build_protobuf_body_without_token_ids(mock_account_ids):
"""Test build protobuf body for a token dissociate transaction without tokenIds."""
account_id, _, _, _, _ = mock_account_ids

tx = TokenDissociateTransaction().set_account_id(account_id)

body = tx._build_proto_body()

assert body is not None
assert body.HasField("account")
assert body.account == account_id._to_proto()

assert len(body.tokens) == 0


def test_build_protobuf_body_missing_both_account_and_token_ids():
"""Test build protobuf body for a token dissociate transaction without accountId and tokenIds."""
tx = TokenDissociateTransaction()

body = tx._build_proto_body()

assert body is not None
assert not body.HasField("account")
assert len(body.tokens) == 0
Loading