Skip to content

Commit 8c61874

Browse files
authored
Merge pull request #32 from exploreriii/TokenDissociateTransaction
TokenDissociateTransaction
2 parents d2f2ce3 + f654be6 commit 8c61874

File tree

5 files changed

+348
-18
lines changed

5 files changed

+348
-18
lines changed

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This is a Python SDK for interacting with the Hedera Hashgraph platform. It allows developers to:
44

5-
- Manage Token Transactions like Create, Associate, Transfer & Delete
5+
- Manage Token Transactions like Create, Associate, Dissociate, Transfer & Delete
66
- Manage Consensus Transactions like Topic Create, Update, Delete
77
- Submit Topic Messages
88
- Query Account Balance, Transaction Receipts, Topic Infos and Messages
@@ -17,6 +17,7 @@ This is a Python SDK for interacting with the Hedera Hashgraph platform. It allo
1717
- [Querying Account Balance](#querying-account-balance)
1818
- [Creating a Token](#creating-a-token)
1919
- [Associating a Token](#associating-a-token)
20+
- [Dissociating a Token](#dissociating-a-token)
2021
- [Transferring Tokens](#transferring-tokens)
2122
- [Deleting a Token](#deleting-a-token)
2223
- [Transferring HBAR](#transferring-hbar)
@@ -107,6 +108,7 @@ New Account Private Key: 228a06c363b0eb328434d51xxx...
107108
New Account Public Key: 8f444e36e8926def492adxxx...
108109
Token creation successful. Token ID: 0.0.5025xxx
109110
Token association successful.
111+
Token dissociation successful.
110112
Token transfer successful.
111113
Token deletion successful.
112114
Topic creation successful.
@@ -229,6 +231,31 @@ transaction = (
229231
transaction.execute(client)
230232
```
231233

234+
### Dissociating a Token
235+
236+
#### Pythonic Syntax:
237+
```
238+
transaction = TokenDissociateTransaction(
239+
account_id=recipient_id,
240+
token_ids=[token_id]
241+
).freeze_with(client)
242+
243+
transaction.sign(recipient_key)
244+
transaction.execute(client)
245+
```
246+
#### Method Chaining:
247+
```
248+
transaction = (
249+
TokenDissociateTransaction()
250+
.set_account_id(recipient_id)
251+
.add_token_id(token_id)
252+
.freeze_with(client)
253+
.sign(recipient_key)
254+
)
255+
256+
transaction.execute(client)
257+
```
258+
232259
### Transferring Tokens
233260

234261
#### Pythonic Syntax:

examples/token_dissociate.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import os
2+
import sys
3+
from dotenv import load_dotenv
4+
5+
from hedera_sdk_python.client.client import Client
6+
from hedera_sdk_python.account.account_id import AccountId
7+
from hedera_sdk_python.crypto.private_key import PrivateKey
8+
from hedera_sdk_python.client.network import Network
9+
from hedera_sdk_python.tokens.token_id import TokenId
10+
from hedera_sdk_python.tokens.token_dissociate_transaction import TokenDissociateTransaction
11+
12+
load_dotenv()
13+
14+
def dissociate_token(): #Single token
15+
network = Network(network='testnet')
16+
client = Client(network)
17+
18+
recipient_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
19+
recipient_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
20+
token_id = TokenId.from_string('TOKEN_ID')
21+
22+
client.set_operator(recipient_id, recipient_key)
23+
24+
transaction = (
25+
TokenDissociateTransaction()
26+
.set_account_id(recipient_id)
27+
.add_token_id(token_id)
28+
.freeze_with(client)
29+
.sign(recipient_key)
30+
)
31+
32+
try:
33+
receipt = transaction.execute(client)
34+
print("Token dissociation successful.")
35+
except Exception as e:
36+
print(f"Token dissociation failed: {str(e)}")
37+
sys.exit(1)
38+
39+
def dissociate_tokens(): # Multiple tokens
40+
network = Network(network='testnet')
41+
client = Client(network)
42+
43+
recipient_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
44+
recipient_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
45+
token_ids = [TokenId.from_string('TOKEN_ID_1'), TokenId.from_string('TOKEN_ID_2')]
46+
47+
client.set_operator(recipient_id, recipient_key)
48+
49+
transaction = (
50+
TokenDissociateTransaction()
51+
.set_account_id(recipient_id)
52+
)
53+
54+
for token_id in token_ids:
55+
transaction.add_token_id(token_id)
56+
57+
transaction = (
58+
transaction
59+
.freeze_with(client)
60+
.sign(recipient_key)
61+
)
62+
63+
try:
64+
receipt = transaction.execute(client)
65+
print("Token dissociations successful.")
66+
except Exception as e:
67+
print(f"Token dissociations failed: {str(e)}")
68+
sys.exit(1)
69+
70+
if __name__ == "__main__":
71+
dissociate_token() # For single token dissociation
72+
# dissociate_tokens() # For multiple token dissociation
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from hedera_sdk_python.transaction.transaction import Transaction
2+
from hedera_sdk_python.hapi.services import token_dissociate_pb2
3+
from hedera_sdk_python.response_code import ResponseCode
4+
5+
class TokenDissociateTransaction(Transaction):
6+
"""
7+
Represents a token dissociate transaction on the Hedera network.
8+
9+
This transaction dissociates the specified tokens with an account,
10+
meaning the account can no longer hold or transact with those tokens.
11+
12+
Inherits from the base Transaction class and implements the required methods
13+
to build and execute a token dissociate transaction.
14+
"""
15+
16+
def __init__(self, account_id=None, token_ids=None):
17+
"""
18+
Initializes a new TokenDissociateTransaction instance with default values.
19+
"""
20+
super().__init__()
21+
self.account_id = account_id
22+
self.token_ids = token_ids or []
23+
24+
self._default_transaction_fee = 500_000_000
25+
26+
def set_account_id(self, account_id):
27+
self._require_not_frozen()
28+
self.account_id = account_id
29+
return self
30+
31+
def add_token_id(self, token_id):
32+
self._require_not_frozen()
33+
self.token_ids.append(token_id)
34+
return self
35+
36+
def build_transaction_body(self):
37+
"""
38+
Builds and returns the protobuf transaction body for token dissociation.
39+
40+
Returns:
41+
TransactionBody: The protobuf transaction body containing the token dissociation details.
42+
43+
Raises:
44+
ValueError: If account ID or token IDs are not set.
45+
"""
46+
if not self.account_id or not self.token_ids:
47+
raise ValueError("Account ID and token IDs must be set.")
48+
49+
token_dissociate_body = token_dissociate_pb2.TokenDissociateTransactionBody(
50+
account=self.account_id.to_proto(),
51+
tokens=[token_id.to_proto() for token_id in self.token_ids]
52+
)
53+
54+
transaction_body = self.build_base_transaction_body()
55+
transaction_body.tokenDissociate.CopyFrom(token_dissociate_body)
56+
57+
return transaction_body
58+
59+
def _execute_transaction(self, client, transaction_proto):
60+
"""
61+
Executes the token dissociation transaction using the provided client.
62+
63+
Args:
64+
client (Client): The client instance to use for execution.
65+
transaction_proto (Transaction): The protobuf Transaction message.
66+
67+
Returns:
68+
TransactionReceipt: The receipt from the network after transaction execution.
69+
70+
Raises:
71+
Exception: If the transaction submission fails or receives an error response.
72+
"""
73+
response = client.token_stub.dissociateTokens(transaction_proto)
74+
75+
if response.nodeTransactionPrecheckCode != ResponseCode.OK:
76+
error_code = response.nodeTransactionPrecheckCode
77+
error_message = ResponseCode.get_name(error_code)
78+
raise Exception(f"Error during transaction submission: {error_code} ({error_message})")
79+
80+
receipt = self.get_receipt(client)
81+
return receipt
82+
83+
def get_receipt(self, client, timeout=60):
84+
"""
85+
Retrieves the receipt for the transaction.
86+
87+
Args:
88+
client (Client): The client instance.
89+
timeout (int): Maximum time in seconds to wait for the receipt.
90+
91+
Returns:
92+
TransactionReceipt: The transaction receipt from the network.
93+
94+
Raises:
95+
Exception: If the transaction ID is not set or if receipt retrieval fails.
96+
"""
97+
if self.transaction_id is None:
98+
raise Exception("Transaction ID is not set.")
99+
100+
receipt = client.get_transaction_receipt(self.transaction_id, timeout)
101+
return receipt

test.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from hedera_sdk_python.crypto.private_key import PrivateKey
99
from hedera_sdk_python.tokens.token_create_transaction import TokenCreateTransaction
1010
from hedera_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction
11+
from hedera_sdk_python.tokens.token_dissociate_transaction import TokenDissociateTransaction
1112
from hedera_sdk_python.transaction.transfer_transaction import TransferTransaction
1213
from hedera_sdk_python.tokens.token_delete_transaction import TokenDeleteTransaction
1314
from hedera_sdk_python.response_code import ResponseCode
@@ -18,7 +19,6 @@
1819
from hedera_sdk_python.consensus.topic_id import TopicId
1920
from hedera_sdk_python.query.topic_info_query import TopicInfoQuery
2021
from hedera_sdk_python.query.account_balance_query import CryptoGetAccountBalanceQuery
21-
2222
load_dotenv()
2323

2424
def load_operator_credentials():
@@ -90,10 +90,10 @@ def create_token(client, operator_id, admin_key):
9090
print(f"Token creation successful. Token ID: {token_id}")
9191
return token_id
9292

93-
def associate_token(client, recipient_id, recipient_private_key, token_id):
93+
def associate_token(client, recipient_id, recipient_private_key, token_ids):
9494
transaction = TokenAssociateTransaction(
9595
account_id=recipient_id,
96-
token_ids=[token_id]
96+
token_ids=token_ids
9797
)
9898
transaction.freeze_with(client)
9999
transaction.sign(client.operator_private_key)
@@ -109,16 +109,34 @@ def associate_token(client, recipient_id, recipient_private_key, token_id):
109109
print(f"Token association failed: {str(e)}")
110110
sys.exit(1)
111111

112-
def transfer_token(client, recipient_id, token_id):
113-
transaction = TransferTransaction(
114-
token_transfers={
115-
token_id: {
116-
client.operator_account_id: -1,
117-
recipient_id: 1,
118-
}
119-
}
120-
).freeze_with(client)
121-
transaction.sign(client.operator_private_key)
112+
def dissociate_token(client, recipient_id, recipient_private_key, token_id):
113+
"""Dissociate the specified token with the recipient account."""
114+
transaction = TokenDissociateTransaction(
115+
account_id = recipient_id,
116+
token_ids = token_id)
117+
transaction.freeze_with(client)
118+
transaction.sign(client.operator_private_key)
119+
transaction.sign(recipient_private_key)
120+
121+
try:
122+
receipt = transaction.execute(client)
123+
if receipt.status != ResponseCode.SUCCESS:
124+
status_message = ResponseCode.get_name(receipt.status)
125+
raise Exception(f"Token dissociation failed with status: {status_message}")
126+
print("Token dissociation successful.")
127+
except Exception as e:
128+
print(f"Token dissociation failed: {str(e)}")
129+
sys.exit(1)
130+
131+
def transfer_token(client, source_id, source_private_key, recipient_id, token_id):
132+
"""Transfer the specified token to the recipient account."""
133+
transaction = (
134+
TransferTransaction()
135+
.add_token_transfer(token_id, source_id, -1)
136+
.add_token_transfer(token_id, recipient_id, 1)
137+
.freeze_with(client)
138+
)
139+
transaction.sign(source_private_key)
122140

123141
try:
124142
receipt = transaction.execute(client)
@@ -248,10 +266,13 @@ def main():
248266
recipient_id, recipient_private_key = create_new_account(client)
249267
query_balance(client, recipient_id)
250268

251-
token_id = create_token(client, operator_id, admin_key)
252-
associate_token(client, recipient_id, recipient_private_key, token_id)
253-
transfer_token(client, recipient_id, token_id)
254-
delete_token(client, token_id, admin_key)
269+
token_id_1 = create_token(client, operator_id, admin_key)
270+
token_id_2 = create_token(client, operator_id, admin_key)
271+
272+
associate_token(client, recipient_id, recipient_private_key, [token_id_1, token_id_2])
273+
transfer_token(client, operator_id, operator_key, recipient_id, token_id_1)
274+
dissociate_token(client, recipient_id, recipient_private_key, [token_id_2])
275+
delete_token(client, token_id_1, admin_key)
255276

256277
topic_id = create_topic(client)
257278
submit_message(client, topic_id)

0 commit comments

Comments
 (0)