Skip to content

Commit 9289d60

Browse files
authored
fix: correct token association check (hiero-ledger#1044)
Signed-off-by: Aubrey Du <[email protected]>
1 parent 23f57a1 commit 9289d60

File tree

2 files changed

+44
-20
lines changed

2 files changed

+44
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
5959

6060
### Fixed
6161

62+
- Fix token association verification in `token_airdrop_transaction.py` to correctly check if tokens are associated by using `token_id in token_balances` instead of incorrectly displaying zero balances which was misleading (#[815])
6263
- Fixed inactivity bot workflow not checking out repository before running (#964)
6364
- Fixed the topic_message_query integarion test
6465
- good first issue template yaml rendering

examples/tokens/token_airdrop_transaction.py

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
TokenAirdropTransaction,
1818
TokenAssociateTransaction,
1919
TokenMintTransaction,
20-
CryptoGetAccountBalanceQuery,
2120
TokenType,
2221
ResponseCode,
2322
NftId,
2423
TransactionRecordQuery,
2524
TokenNftInfoQuery
2625
)
26+
from hiero_sdk_python.query.account_info_query import AccountInfoQuery
2727

2828
load_dotenv()
2929
network_name = os.getenv('NETWORK', 'testnet').lower()
@@ -139,14 +139,16 @@ def associate_tokens(client, recipient_id, recipient_key, tokens):
139139
assocciate_tx.sign(recipient_key)
140140
assocciate_tx.execute(client)
141141

142-
balance_before = (
143-
CryptoGetAccountBalanceQuery(account_id=recipient_id)
144-
.execute(client)
145-
.token_balances
146-
)
147-
print("Tokens associated with recipient:")
148-
print(f"{tokens[0]}: {balance_before.get(tokens[0])}")
149-
print(f"{tokens[1]}: {balance_before.get(tokens[1])}")
142+
# Use AccountInfoQuery to check token associations
143+
info = AccountInfoQuery(account_id=recipient_id).execute(client)
144+
145+
# Get the list of associated token IDs from token_relationships
146+
associated_token_ids = [rel.token_id for rel in info.token_relationships]
147+
148+
print("\nTokens associated with recipient:")
149+
for token_id in tokens:
150+
associated = token_id in associated_token_ids
151+
print(f" {token_id}: {'Associated' if associated else 'NOT Associated'}")
150152

151153
print("\n✅ Success! Token association complete.")
152154

@@ -282,6 +284,7 @@ def verify_post_airdrop_balances(
282284
):
283285
"""
284286
Verify post-airdrop balances and NFT ownership to confirm successful transfer.
287+
Uses AccountInfoQuery for robust token association and balance verification.
285288
Accepts a `balances_before` mapping with keys 'sender' and 'recipient'.
286289
Returns (fully_verified_bool, details_dict)
287290
"""
@@ -298,18 +301,20 @@ def verify_post_airdrop_balances(
298301
"record_checks": record_verification,
299302
}
300303

301-
# Get current balances (fail-fast is not desired; capture errors in details)
304+
# Get current account info and balances using AccountInfoQuery (more robust)
302305
try:
303-
sender_current = CryptoGetAccountBalanceQuery(account_id=operator_id).execute(client).token_balances
306+
sender_info = AccountInfoQuery(account_id=operator_id).execute(client)
307+
sender_current = {rel.token_id: rel.balance for rel in sender_info.token_relationships}
304308
except Exception as e:
305-
details["error"] = f"Error fetching sender balance: {e}"
309+
details["error"] = f"Error fetching sender account info: {e}"
306310
details["fully_verified"] = False
307311
return False, details
308312

309313
try:
310-
recipient_current = CryptoGetAccountBalanceQuery(account_id=recipient_id).execute(client).token_balances
314+
recipient_info = AccountInfoQuery(account_id=recipient_id).execute(client)
315+
recipient_current = {rel.token_id: rel.balance for rel in recipient_info.token_relationships}
311316
except Exception as e:
312-
details["error"] = f"Error fetching recipient balance: {e}"
317+
details["error"] = f"Error fetching recipient account info: {e}"
313318
details["fully_verified"] = False
314319
return False, details
315320

@@ -349,16 +354,24 @@ def verify_post_airdrop_balances(
349354

350355

351356
def _log_balances_before(client, operator_id, recipient_id, token_id, nft_id):
352-
"""Fetch and print sender/recipient token balances before airdrop."""
353-
print("\nStep 5: Checking balances before airdrop...")
354-
sender_balances_before = CryptoGetAccountBalanceQuery(account_id=operator_id).execute(client).token_balances
355-
recipient_balances_before = CryptoGetAccountBalanceQuery(account_id=recipient_id).execute(client).token_balances
357+
"""Fetch and print sender/recipient token balances and associations before airdrop."""
358+
print("\nStep 5: Checking balances and associations before airdrop...")
359+
360+
# Get account info to verify associations
361+
sender_info = AccountInfoQuery(account_id=operator_id).execute(client)
362+
recipient_info = AccountInfoQuery(account_id=recipient_id).execute(client)
363+
364+
# Build dictionaries for balances from token_relationships (more robust than balance query)
365+
sender_balances_before = {rel.token_id: rel.balance for rel in sender_info.token_relationships}
366+
recipient_balances_before = {rel.token_id: rel.balance for rel in recipient_info.token_relationships}
367+
356368
print(f"Sender ({operator_id}) balances before airdrop:")
357369
print(f" {token_id}: {sender_balances_before.get(token_id, 0)}")
358370
print(f" {nft_id}: {sender_balances_before.get(nft_id, 0)}")
359371
print(f"Recipient ({recipient_id}) balances before airdrop:")
360372
print(f" {token_id}: {recipient_balances_before.get(token_id, 0)}")
361373
print(f" {nft_id}: {recipient_balances_before.get(nft_id, 0)}")
374+
362375
return sender_balances_before, recipient_balances_before
363376

364377

@@ -377,8 +390,18 @@ def _print_verification_summary(record_result, verification_details, operator_id
377390

378391
def _print_final_summary(client, operator_id, recipient_id, token_id, nft_id, serial_number, verification_details):
379392
"""Print final balances after airdrop and a small summary table."""
380-
sender_balances_after = verification_details.get("sender_balances_after") or CryptoGetAccountBalanceQuery(account_id=operator_id).execute(client).token_balances
381-
recipient_balances_after = verification_details.get("recipient_balances_after") or CryptoGetAccountBalanceQuery(account_id=recipient_id).execute(client).token_balances
393+
# Use AccountInfoQuery for accurate balance retrieval if not already cached
394+
if verification_details.get("sender_balances_after") is None:
395+
sender_info = AccountInfoQuery(account_id=operator_id).execute(client)
396+
sender_balances_after = {rel.token_id: rel.balance for rel in sender_info.token_relationships}
397+
else:
398+
sender_balances_after = verification_details.get("sender_balances_after")
399+
400+
if verification_details.get("recipient_balances_after") is None:
401+
recipient_info = AccountInfoQuery(account_id=recipient_id).execute(client)
402+
recipient_balances_after = {rel.token_id: rel.balance for rel in recipient_info.token_relationships}
403+
else:
404+
recipient_balances_after = verification_details.get("recipient_balances_after")
382405

383406
print("\nBalances after airdrop:")
384407
print(f"Sender ({operator_id}):")

0 commit comments

Comments
 (0)