Skip to content

Commit b8569d3

Browse files
Dosik130xivanov
andauthored
feat: add TransactionRecordQuery (#144)
* feat: add transaction_id field to TransactionReceipt Signed-off-by: dosi <[email protected]> * refactor: store transaction_id in TransactionReceipt Signed-off-by: dosi <[email protected]> * feat: add _from_proto() to TokenNftTransfer Signed-off-by: dosi <[email protected]> * test: add unit test for TokenNftTransfer _from_proto() Signed-off-by: dosi <[email protected]> * test: add unit tests for TransactionRecord Signed-off-by: dosi <[email protected]> * feat: implement TransactionRecord class Signed-off-by: dosi <[email protected]> * sqash s transaction record Signed-off-by: dosi <[email protected]> * feat: implement TransactionRecordQuery Signed-off-by: dosi <[email protected]> * test: implement integration tests for TransactionRecordQuery Signed-off-by: dosi <[email protected]> * test: add unit tests Signed-off-by: dosi <[email protected]> * docs: add query record example Signed-off-by: dosi <[email protected]> * chore: add TransactionRecord and TransactionRecordQuery to __init__.py Signed-off-by: dosi <[email protected]> * docs: add transaction record query to README Signed-off-by: dosi <[email protected]> * test: reduce test_transaction_record_query_execute() lines in TransactionRecordQuery unit tests Signed-off-by: dosi <[email protected]> * feat: add __repr__ method Signed-off-by: Ivan Ivanov <[email protected]> --------- Signed-off-by: dosi <[email protected]> Signed-off-by: Ivan Ivanov <[email protected]> Co-authored-by: Ivan Ivanov <[email protected]>
1 parent 366c783 commit b8569d3

13 files changed

+1127
-6
lines changed

examples/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ You can choose either syntax or even mix both styles in your projects.
4545
- [Deleting a Topic](#deleting-a-topic)
4646
- [Querying Topic](#querying-topic)
4747
- [Querying Topic Message](#querying-topic-message)
48+
- [Miscellaneous Queries](#miscellaneous-queries)
49+
- [Querying Transaction Record](#querying-transaction-record)
4850

4951

5052
## Account Transactions
@@ -876,4 +878,37 @@ query = (
876878
)
877879
878880
query.subscribe(client)
881+
```
882+
883+
## Miscellaneous Queries
884+
885+
### Querying Transaction Record
886+
887+
#### Pythonic Syntax:
888+
```
889+
query = TransactionRecordQuery(
890+
transaction_id=transaction_id
891+
)
892+
893+
record = query.execute(client)
894+
895+
print(f"Transaction ID: {record.transaction_id}")
896+
print(f"Transaction Fee: {record.transaction_fee}")
897+
print(f"Transaction Hash: {record.transaction_hash}")
898+
print(f"Transaction Memo: {record.transaction_memo}")
899+
print(f"Transaction Account ID: {record.receipt.accountId}")
900+
```
901+
#### Method Chaining:
902+
```
903+
record = (
904+
TransactionRecordQuery()
905+
.set_transaction_id(transaction_id)
906+
.execute(client)
907+
)
908+
909+
print(f"Transaction ID: {record.transaction_id}")
910+
print(f"Transaction Fee: {record.transaction_fee}")
911+
print(f"Transaction Hash: {record.transaction_hash}")
912+
print(f"Transaction Memo: {record.transaction_memo}")
913+
print(f"Transaction Account ID: {record.receipt.accountId}")
879914
```

examples/query_record.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import os
2+
import sys
3+
from dotenv import load_dotenv
4+
5+
from hiero_sdk_python import (
6+
Client,
7+
AccountId,
8+
PrivateKey,
9+
Network,
10+
Hbar,
11+
)
12+
from hiero_sdk_python.account.account_create_transaction import AccountCreateTransaction
13+
from hiero_sdk_python.query.transaction_record_query import TransactionRecordQuery
14+
from hiero_sdk_python.response_code import ResponseCode
15+
from hiero_sdk_python.tokens.supply_type import SupplyType
16+
from hiero_sdk_python.tokens.token_associate_transaction import TokenAssociateTransaction
17+
from hiero_sdk_python.tokens.token_create_transaction import TokenCreateTransaction
18+
from hiero_sdk_python.tokens.token_type import TokenType
19+
from hiero_sdk_python.transaction.transfer_transaction import TransferTransaction
20+
21+
load_dotenv()
22+
23+
def setup_client():
24+
"""Initialize and set up the client with operator account"""
25+
# Initialize network and client
26+
network = Network(network='testnet')
27+
client = Client(network)
28+
29+
# Set up operator account
30+
operator_id = AccountId.from_string(os.getenv('OPERATOR_ID'))
31+
operator_key = PrivateKey.from_string(os.getenv('OPERATOR_KEY'))
32+
client.set_operator(operator_id, operator_key)
33+
34+
return client, operator_id, operator_key
35+
36+
def create_account_transaction(client):
37+
"""Create a new account to get a transaction ID for record query"""
38+
# Generate a new key pair for the account
39+
new_account_key = PrivateKey.generate_ed25519()
40+
41+
# Create the account
42+
receipt = (
43+
AccountCreateTransaction()
44+
.set_key(new_account_key.public_key())
45+
.set_initial_balance(Hbar(1))
46+
.execute(client)
47+
)
48+
49+
# Check if account creation was successful
50+
if receipt.status != ResponseCode.SUCCESS:
51+
print(f"Account creation failed with status: {ResponseCode(receipt.status).name}")
52+
sys.exit(1)
53+
54+
# Get the new account ID and transaction ID from receipt
55+
new_account_id = receipt.accountId
56+
transaction_id = receipt.transaction_id
57+
58+
print(f"Account created with ID: {new_account_id}")
59+
60+
return new_account_id, new_account_key, transaction_id
61+
62+
def create_fungible_token(client: 'Client', account_id, account_private_key):
63+
"""Create a fungible token"""
64+
receipt = (
65+
TokenCreateTransaction()
66+
.set_token_name("MyExampleFT")
67+
.set_token_symbol("EXFT")
68+
.set_decimals(2)
69+
.set_initial_supply(100)
70+
.set_treasury_account_id(account_id)
71+
.set_token_type(TokenType.FUNGIBLE_COMMON)
72+
.set_supply_type(SupplyType.FINITE)
73+
.set_max_supply(1000)
74+
.set_admin_key(account_private_key)
75+
.set_supply_key(account_private_key)
76+
.execute(client)
77+
)
78+
79+
if receipt.status != ResponseCode.SUCCESS:
80+
print(f"Fungible token creation failed with status: {ResponseCode(receipt.status).name}")
81+
sys.exit(1)
82+
83+
token_id = receipt.tokenId
84+
print(f"\nFungible token created with ID: {token_id}")
85+
86+
return token_id
87+
88+
def associate_token(client, token_id, receiver_id, receiver_private_key):
89+
"""Associate token with an account"""
90+
# Associate the token_id with the new account
91+
receipt = (
92+
TokenAssociateTransaction()
93+
.set_account_id(receiver_id)
94+
.add_token_id(token_id)
95+
.freeze_with(client)
96+
.sign(receiver_private_key) # Has to be signed here by receiver's key
97+
.execute(client)
98+
)
99+
100+
if receipt.status != ResponseCode.SUCCESS:
101+
print(f"Token association failed with status: {ResponseCode(receipt.status).name}")
102+
sys.exit(1)
103+
104+
print(f"Token successfully associated with account: {receiver_id}")
105+
106+
def transfer_tokens(client, treasury_id, treasury_private_key, receiver_id, token_id, amount=10):
107+
"""Transfer tokens to the receiver account so we can later reject them"""
108+
# Transfer tokens to the receiver account
109+
receipt = (
110+
TransferTransaction()
111+
.add_token_transfer(token_id, treasury_id, -amount)
112+
.add_token_transfer(token_id, receiver_id, amount)
113+
.freeze_with(client)
114+
.sign(treasury_private_key)
115+
.execute(client)
116+
)
117+
118+
# Check if transfer was successful
119+
if receipt.status != ResponseCode.SUCCESS:
120+
print(f"Transfer failed with status: {ResponseCode(receipt.status).name}")
121+
sys.exit(1)
122+
123+
print(f"Successfully transferred {amount} tokens to receiver account {receiver_id}")
124+
125+
return receipt
126+
127+
def print_transaction_record(record):
128+
"""Print the transaction record"""
129+
print(f"Transaction ID: {record.transaction_id}")
130+
print(f"Transaction Fee: {record.transaction_fee}")
131+
print(f"Transaction Hash: {record.transaction_hash.hex()}")
132+
print(f"Transaction Memo: {record.transaction_memo}")
133+
print(f"Transaction Account ID: {record.receipt.accountId}")
134+
135+
print(f"\nTransfers made in the transaction:")
136+
for account_id, amount in record.transfers.items():
137+
print(f" Account: {account_id}, Amount: {amount}")
138+
139+
def query_record():
140+
"""
141+
Demonstrates the transaction record query functionality by performing the following steps:
142+
1. Creating a new account transaction to get a transaction ID
143+
2. Querying and displaying the transaction record for account creation
144+
3. Creating a fungible token and associating it with the new account
145+
4. Transferring tokens from operator to new account
146+
5. Querying and displaying the transaction record for token transfer
147+
"""
148+
client, operator_id, operator_key = setup_client()
149+
150+
# Create a transaction to get a transaction ID
151+
new_account_id, new_account_key, transaction_id = create_account_transaction(client)
152+
153+
record = (
154+
TransactionRecordQuery()
155+
.set_transaction_id(transaction_id)
156+
.execute(client)
157+
)
158+
print("Transaction record for account creation:")
159+
print_transaction_record(record)
160+
161+
token_id = create_fungible_token(client, operator_id, operator_key)
162+
associate_token(client, token_id, new_account_id, new_account_key)
163+
transfer_receipt = transfer_tokens(client, operator_id, operator_key, new_account_id, token_id)
164+
165+
transfer_record = (
166+
TransactionRecordQuery()
167+
.set_transaction_id(transfer_receipt.transaction_id)
168+
.execute(client)
169+
)
170+
print("Transaction record for token transfer:")
171+
print_transaction_record(transfer_record)
172+
173+
print(f"\nToken Transfer Record:")
174+
for token_id, transfers in transfer_record.token_transfers.items():
175+
print(f" Token ID: {token_id}")
176+
for account_id, amount in transfers.items():
177+
print(f" Account: {account_id}, Amount: {amount}")
178+
179+
if __name__ == "__main__":
180+
query_record()

src/hiero_sdk_python/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from .transaction.transaction_id import TransactionId
3939
from .transaction.transaction_receipt import TransactionReceipt
4040
from .transaction.transaction_response import TransactionResponse
41+
from .transaction.transaction_record import TransactionRecord
4142

4243
# Response / Codes
4344
from .response_code import ResponseCode
@@ -62,6 +63,7 @@
6263
from .query.topic_info_query import TopicInfoQuery
6364
from .query.topic_message_query import TopicMessageQuery
6465
from .query.transaction_get_receipt_query import TransactionGetReceiptQuery
66+
from .query.transaction_record_query import TransactionRecordQuery
6567
from .query.account_balance_query import CryptoGetAccountBalanceQuery
6668
from .query.token_nft_info_query import TokenNftInfoQuery
6769
from .query.token_info_query import TokenInfoQuery
@@ -116,6 +118,7 @@
116118
"TransactionId",
117119
"TransactionReceipt",
118120
"TransactionResponse",
121+
"TransactionRecord",
119122

120123
# Response
121124
"ResponseCode",
@@ -131,6 +134,7 @@
131134
"TopicInfoQuery",
132135
"TopicMessageQuery",
133136
"TransactionGetReceiptQuery",
137+
"TransactionRecordQuery",
134138
"CryptoGetAccountBalanceQuery",
135139
"TokenNftInfoQuery",
136140
"TokenInfoQuery",

src/hiero_sdk_python/account/account_id.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,17 @@ def __str__(self) -> str:
6666
"""
6767
return f"{self.shard}.{self.realm}.{self.num}"
6868

69+
def __repr__(self):
70+
"""
71+
Returns the repr representation of the AccountId.
72+
"""
73+
return f"AccountId(shard={self.shard}, realm={self.realm}, num={self.num})"
74+
75+
def __eq__(self, other):
76+
if not isinstance(other, AccountId):
77+
return False
78+
return (self.shard, self.realm, self.num) == (other.shard, other.realm, other.num)
79+
6980
def __eq__(self, other: object) -> bool:
7081
"""
7182
Checks equality between two AccountId instances.

src/hiero_sdk_python/query/transaction_get_receipt_query.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def execute(self, client: Client) -> TransactionReceipt:
219219
self._before_execute(client)
220220
response = self._execute(client)
221221

222-
return TransactionReceipt._from_proto(response.transactionGetReceipt.receipt)
222+
return TransactionReceipt._from_proto(response.transactionGetReceipt.receipt, self.transaction_id)
223223

224224
def _get_query_response(self, response: response_pb2.Response) -> transaction_get_receipt_pb2.TransactionGetReceiptResponse:
225225
"""

0 commit comments

Comments
 (0)