Transaction Lookup
Description
Section titled “Description”This example demonstrates how to lookup a single transaction by ID using the IndexerClient lookup_transaction_by_id() method. Prerequisites:
Prerequisites
Section titled “Prerequisites”- LocalNet running (via
algokit localnet start)
Run This Example
Section titled “Run This Example”From the repository’s examples directory:
cd examplesuv run python indexer_client/06_transaction_lookup.py# ruff: noqa: N999, C901, PLR0912, PLR0915, PLR2004"""Example: Transaction Lookup
This example demonstrates how to lookup a single transaction by ID usingthe IndexerClient lookup_transaction_by_id() method.
Prerequisites:- LocalNet running (via `algokit localnet start`)"""
import base64import timefrom datetime import datetime, timezone
from shared import ( create_algorand_client, create_indexer_client, format_micro_algo, print_error, print_header, print_info, print_step, print_success, shorten_address,)
from algokit_utils import AlgoAmount, AssetCreateParams, AssetOptInParams, AssetTransferParams, PaymentParams
def main() -> None: print_header("Transaction Lookup Example")
# Create clients indexer = create_indexer_client() algorand = create_algorand_client()
# ========================================================================= # Step 1: Get a funded account from LocalNet # ========================================================================= print_step(1, "Getting a funded account from LocalNet")
try: sender = algorand.account.localnet_dispenser() algorand.set_signer_from_account(sender) sender_address = sender.addr print_success(f"Using dispenser account: {shorten_address(sender_address)}") except Exception as e: print_error(f"Failed to get dispenser account: {e}") print_info("") print_info("Make sure LocalNet is running: algokit localnet start") print_info("If issues persist, try: algokit localnet reset") return
# ========================================================================= # Step 2: Create a test transaction and capture its txId # ========================================================================= print_step(2, "Creating a test transaction and capturing its txId")
try: # Create a random receiver account receiver = algorand.account.random() receiver_address = receiver.addr algorand.set_signer_from_account(receiver) print_info(f"Created receiver account: {shorten_address(receiver_address)}")
# Send a payment transaction print_info("Sending payment transaction...") payment_result = algorand.send.payment( PaymentParams( sender=sender_address, receiver=receiver_address, amount=AlgoAmount.from_algo(5), ) ) payment_tx_id = payment_result.tx_ids[0] print_success(f"Payment transaction sent: {shorten_address(payment_tx_id, 8, 6)}") print_info(f" Full txId: {payment_tx_id}")
# Create an asset for asset transfer demonstration print_info("Creating a test asset...") asset_create_result = algorand.send.asset_create( AssetCreateParams( sender=sender_address, total=1_000_000, decimals=6, asset_name="LookupToken", unit_name="LOOK", ) ) asset_id = asset_create_result.asset_id print_success(f"Created asset: LookupToken (ID: {asset_id})")
# Opt-in receiver to the asset print_info("Opting receiver into asset...") algorand.send.asset_opt_in( AssetOptInParams( sender=receiver_address, asset_id=asset_id, ) ) print_success("Receiver opted into asset")
# Send an asset transfer transaction print_info("Sending asset transfer transaction...") asset_transfer_result = algorand.send.asset_transfer( AssetTransferParams( sender=sender_address, receiver=receiver_address, asset_id=asset_id, amount=50_000, ) ) asset_transfer_tx_id = asset_transfer_result.tx_ids[0] print_success(f"Asset transfer transaction sent: {shorten_address(asset_transfer_tx_id, 8, 6)}") print_info(f" Full txId: {asset_transfer_tx_id}")
# Wait for indexer to catch up print_info("Waiting for indexer to index transactions...") time.sleep(3) print_info("") except Exception as e: print_error(f"Failed to create test transactions: {e}") print_info("") print_info("If LocalNet errors occur, try: algokit localnet reset") return
# ========================================================================= # Step 3: Lookup payment transaction by ID # ========================================================================= print_step(3, "Looking up payment transaction by ID")
try: txn_result = indexer.lookup_transaction_by_id(payment_tx_id) tx = txn_result.transaction
print_success("Transaction found!") print_info("") print_info("Common transaction fields:") print_info(f" - id: {tx.id_}") print_info(f" - tx_type: {tx.tx_type}") print_info(f" - sender: {shorten_address(tx.sender)}") print_info(f" - fee: {format_micro_algo(tx.fee)}") print_info(f" - first_valid: {tx.first_valid}") print_info(f" - last_valid: {tx.last_valid}") print_info("")
print_info("Confirmation info:") if tx.confirmed_round is not None: print_info(f" - confirmed_round: {tx.confirmed_round}") if tx.round_time is not None: date = datetime.fromtimestamp(tx.round_time, tz=timezone.utc) print_info(f" - round_time: {date.isoformat()} (Unix: {tx.round_time})") if tx.intra_round_offset is not None: print_info(f" - intra_round_offset: {tx.intra_round_offset}") print_info("")
# Display payment-specific fields if tx.payment_transaction: print_info("Payment transaction details:") print_info(f" - receiver: {shorten_address(tx.payment_transaction.receiver)}") print_info(f" - amount: {format_micro_algo(tx.payment_transaction.amount)}") if tx.payment_transaction.close_remainder_to: print_info(f" - close_remainder_to: {shorten_address(tx.payment_transaction.close_remainder_to)}") if tx.payment_transaction.close_amount is not None: print_info(f" - close_amount: {format_micro_algo(tx.payment_transaction.close_amount)}")
print_info("") print_info(f"Query performed at round: {txn_result.current_round}") except Exception as e: print_error(f"lookup_transaction_by_id failed: {e}")
# ========================================================================= # Step 4: Lookup asset transfer transaction by ID # ========================================================================= print_step(4, "Looking up asset transfer transaction by ID")
try: txn_result = indexer.lookup_transaction_by_id(asset_transfer_tx_id) tx = txn_result.transaction
print_success("Transaction found!") print_info("") print_info("Common transaction fields:") print_info(f" - id: {tx.id_}") print_info(f" - tx_type: {tx.tx_type}") print_info(f" - sender: {shorten_address(tx.sender)}") print_info(f" - fee: {format_micro_algo(tx.fee)}") print_info(f" - first_valid: {tx.first_valid}") print_info(f" - last_valid: {tx.last_valid}") print_info("")
print_info("Confirmation info:") if tx.confirmed_round is not None: print_info(f" - confirmed_round: {tx.confirmed_round}") if tx.round_time is not None: date = datetime.fromtimestamp(tx.round_time, tz=timezone.utc) print_info(f" - round_time: {date.isoformat()} (Unix: {tx.round_time})") if tx.intra_round_offset is not None: print_info(f" - intra_round_offset: {tx.intra_round_offset}") print_info("")
# Display asset transfer-specific fields if tx.asset_transfer_transaction: print_info("Asset transfer transaction details:") print_info(f" - asset_id: {tx.asset_transfer_transaction.asset_id}") print_info(f" - amount: {tx.asset_transfer_transaction.amount}") print_info(f" - receiver: {shorten_address(tx.asset_transfer_transaction.receiver)}") if tx.asset_transfer_transaction.sender: print_info(f" - sender (clawback): {shorten_address(tx.asset_transfer_transaction.sender)}") if tx.asset_transfer_transaction.close_to: print_info(f" - close_to: {shorten_address(tx.asset_transfer_transaction.close_to)}") if tx.asset_transfer_transaction.close_amount is not None: print_info(f" - close_amount: {tx.asset_transfer_transaction.close_amount}")
print_info("") print_info(f"Query performed at round: {txn_result.current_round}") except Exception as e: print_error(f"lookup_transaction_by_id failed: {e}")
# ========================================================================= # Step 5: Handle transaction not found case # ========================================================================= print_step(5, "Handling transaction not found case")
try: # Use a fake transaction ID that doesn't exist (valid base32 format, 52 chars) fake_tx_id = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" print_info(f"Attempting to lookup non-existent transaction: {shorten_address(fake_tx_id, 8, 6)}")
indexer.lookup_transaction_by_id(fake_tx_id)
# If we get here, the transaction was somehow found (shouldn't happen) print_info("Transaction was unexpectedly found") except Exception as e: error_message = str(e) if "not found" in error_message.lower() or "no transactions" in error_message.lower(): print_success("Transaction not found - error handled correctly") print_info(f" Error message: {error_message}") else: print_error(f"Unexpected error: {error_message}")
# ========================================================================= # Step 6: Display additional transaction fields (if available) # ========================================================================= print_step(6, "Displaying additional transaction fields")
try: txn_result = indexer.lookup_transaction_by_id(payment_tx_id) tx = txn_result.transaction
print_info("Additional fields (if present):")
if tx.genesis_id: print_info(f" - genesis_id: {tx.genesis_id}")
if tx.genesis_hash: if isinstance(tx.genesis_hash, bytes): hash_b64 = base64.b64encode(tx.genesis_hash).decode() else: hash_b64 = tx.genesis_hash hash_preview = hash_b64[:20] if len(hash_b64) > 20 else hash_b64 print_info(f" - genesis_hash: {hash_preview}...")
if tx.group: group_b64 = base64.b64encode(tx.group).decode() if isinstance(tx.group, bytes) else tx.group print_info(f" - group: {group_b64}")
if tx.note: try: note_bytes = tx.note if isinstance(tx.note, bytes) else base64.b64decode(tx.note) note_text = note_bytes.decode("utf-8") if note_bytes else "(empty)" except Exception: note_text = "(binary data)" print_info(f" - note: {note_text}")
if tx.lease: lease_b64 = base64.b64encode(tx.lease).decode() if isinstance(tx.lease, bytes) else tx.lease print_info(f" - lease: {lease_b64}")
if tx.rekey_to: print_info(f" - rekey_to: {tx.rekey_to}")
if tx.sender_rewards is not None: print_info(f" - sender_rewards: {format_micro_algo(tx.sender_rewards)}")
if tx.receiver_rewards is not None: print_info(f" - receiver_rewards: {format_micro_algo(tx.receiver_rewards)}")
if tx.close_rewards is not None: print_info(f" - close_rewards: {format_micro_algo(tx.close_rewards)}")
if tx.closing_amount is not None: print_info(f" - closing_amount: {format_micro_algo(tx.closing_amount)}")
if tx.auth_addr: print_info(f" - auth_addr: {tx.auth_addr}")
if tx.signature: print_info(" - signature: (present)") if hasattr(tx.signature, "sig") and tx.signature.sig: print_info(" - type: single signature") if hasattr(tx.signature, "multisig") and tx.signature.multisig: print_info(" - type: multisig") if hasattr(tx.signature, "logicsig") and tx.signature.logicsig: print_info(" - type: logic signature")
# Check for created assets or applications if tx.created_asset_id is not None: print_info(f" - created_asset_id: {tx.created_asset_id}") if tx.created_app_id is not None: print_info(f" - created_app_id: {tx.created_app_id}")
# Inner transactions (for app calls) if tx.inner_txns and len(tx.inner_txns) > 0: print_info(f" - inner_txns: {len(tx.inner_txns)} inner transaction(s)")
# Logs (for app calls) if tx.logs and len(tx.logs) > 0: print_info(f" - logs: {len(tx.logs)} log entry(ies)")
# State deltas (for app calls) if tx.global_state_delta: print_info(" - global_state_delta: (present)") if tx.local_state_delta and len(tx.local_state_delta) > 0: print_info(f" - local_state_delta: {len(tx.local_state_delta)} account(s) affected") except Exception as e: print_error(f"Failed to display additional fields: {e}")
# ========================================================================= # Summary # ========================================================================= print_header("Summary") print_info("This example demonstrated:") print_info(" 1. lookup_transaction_by_id(txId) - Get full transaction details by ID") print_info(" 2. Displaying common transaction fields: id, tx_type, sender, fee, first_valid, last_valid") print_info(" 3. Displaying confirmation info: confirmed_round, round_time, intra_round_offset") print_info(" 4. Displaying payment-specific fields: receiver, amount, close_remainder_to") print_info(" 5. Displaying asset transfer-specific fields: asset_id, amount, receiver") print_info(" 6. Handling transaction not found errors") print_info(" 7. Displaying additional fields: genesis_id, note, signature, etc.") print_info("") print_info("TransactionResponse structure:") print_info(" - transaction: The full Transaction object") print_info(" - current_round: Round at which the results were computed") print_info("") print_info("Key Transaction fields:") print_info(" - id: Transaction ID (string)") print_info(" - tx_type: Transaction type (pay, keyreg, acfg, axfer, afrz, appl, stpf, hb)") print_info(" - sender: Sender address (string)") print_info(" - fee: Transaction fee in microAlgos (int)") print_info(" - first_valid: First valid round (int)") print_info(" - last_valid: Last valid round (int)") print_info(" - confirmed_round: Round when confirmed (int, optional)") print_info(" - round_time: Unix timestamp when confirmed (int, optional)") print_info(" - intra_round_offset: Position within the round (int, optional)") print_info("") print_info("Type-specific fields:") print_info(" - payment_transaction: { receiver, amount, close_remainder_to, close_amount }") print_info(" - asset_transfer_transaction: { asset_id, amount, receiver, sender, close_to, close_amount }") print_info(" - asset_config_transaction: { asset_id, params }") print_info(" - application_transaction: { application_id, on_complete, accounts, etc. }")
if __name__ == "__main__": main()