Transaction Lookup
Description
Section titled “Description”This example demonstrates how to lookup a single transaction by ID using the IndexerClient lookupTransactionById() method.
Prerequisites
Section titled “Prerequisites”- LocalNet running (via
algokit localnet start)
Run This Example
Section titled “Run This Example”From the repository root:
cd examplesnpm run example indexer_client/06-transaction-lookup.ts/** * Example: Transaction Lookup * * This example demonstrates how to lookup a single transaction by ID using * the IndexerClient lookupTransactionById() method. * * Prerequisites: * - LocalNet running (via `algokit localnet start`) */
import { algo } from '@algorandfoundation/algokit-utils';import { createAlgorandClient, createIndexerClient, formatMicroAlgo, printError, printHeader, printInfo, printStep, printSuccess, shortenAddress,} from '../shared/utils.js';
async function main() { printHeader('Transaction Lookup Example');
// Create clients const indexer = createIndexerClient(); const algorand = createAlgorandClient();
// ========================================================================= // Step 1: Get a funded account from LocalNet // ========================================================================= printStep(1, 'Getting a funded account from LocalNet');
let senderAccount: Awaited<ReturnType<typeof algorand.account.kmd.getLocalNetDispenserAccount>>;
try { senderAccount = await algorand.account.kmd.getLocalNetDispenserAccount(); algorand.setSignerFromAccount(senderAccount); const senderAddress = senderAccount.addr.toString(); printSuccess(`Using dispenser account: ${shortenAddress(senderAddress)}`); } catch (error) { printError( `Failed to get dispenser account: ${error instanceof Error ? error.message : String(error)}`, ); printInfo(''); printInfo('Make sure LocalNet is running: algokit localnet start'); printInfo('If issues persist, try: algokit localnet reset'); return; }
// ========================================================================= // Step 2: Create a test transaction and capture its txId // ========================================================================= printStep(2, 'Creating a test transaction and capturing its txId');
let paymentTxId: string; let assetTransferTxId: string; let assetId: bigint; let receiverAddress: string;
try { // Create a random receiver account const receiverAccount = algorand.account.random(); receiverAddress = receiverAccount.addr.toString(); algorand.setSignerFromAccount(receiverAccount); printInfo(`Created receiver account: ${shortenAddress(receiverAddress)}`);
// Send a payment transaction printInfo('Sending payment transaction...'); const paymentResult = await algorand.send.payment({ sender: senderAccount.addr, receiver: receiverAccount.addr, amount: algo(5), }); paymentTxId = paymentResult.txIds[0]; printSuccess(`Payment transaction sent: ${shortenAddress(paymentTxId, 8, 6)}`); printInfo(` Full txId: ${paymentTxId}`);
// Create an asset for asset transfer demonstration printInfo('Creating a test asset...'); const assetCreateResult = await algorand.send.assetCreate({ sender: senderAccount.addr, total: 1_000_000n, decimals: 6, assetName: 'LookupToken', unitName: 'LOOK', }); assetId = assetCreateResult.assetId; printSuccess(`Created asset: LookupToken (ID: ${assetId})`);
// Opt-in receiver to the asset printInfo('Opting receiver into asset...'); await algorand.send.assetOptIn({ sender: receiverAccount.addr, assetId: assetId, }); printSuccess('Receiver opted into asset');
// Send an asset transfer transaction printInfo('Sending asset transfer transaction...'); const assetTransferResult = await algorand.send.assetTransfer({ sender: senderAccount.addr, receiver: receiverAccount.addr, assetId: assetId, amount: 50_000n, }); assetTransferTxId = assetTransferResult.txIds[0]; printSuccess(`Asset transfer transaction sent: ${shortenAddress(assetTransferTxId, 8, 6)}`); printInfo(` Full txId: ${assetTransferTxId}`);
// Wait for indexer to catch up printInfo('Waiting for indexer to index transactions...'); await new Promise(resolve => setTimeout(resolve, 3000)); printInfo(''); } catch (error) { printError( `Failed to create test transactions: ${error instanceof Error ? error.message : String(error)}`, ); printInfo(''); printInfo('If LocalNet errors occur, try: algokit localnet reset'); return; }
// ========================================================================= // Step 3: Lookup payment transaction by ID // ========================================================================= printStep(3, 'Looking up payment transaction by ID');
try { const txnResult = await indexer.lookupTransactionById(paymentTxId); const tx = txnResult.transaction;
printSuccess(`Transaction found!`); printInfo(''); printInfo('Common transaction fields:'); printInfo(` - id: ${tx.id}`); printInfo(` - txType: ${tx.txType}`); printInfo(` - sender: ${shortenAddress(tx.sender)}`); printInfo(` - fee: ${formatMicroAlgo(tx.fee)}`); printInfo(` - firstValid: ${tx.firstValid}`); printInfo(` - lastValid: ${tx.lastValid}`); printInfo('');
printInfo('Confirmation info:'); if (tx.confirmedRound !== undefined) { printInfo(` - confirmedRound: ${tx.confirmedRound}`); } if (tx.roundTime !== undefined) { const date = new Date(tx.roundTime * 1000); printInfo(` - roundTime: ${date.toISOString()} (Unix: ${tx.roundTime})`); } if (tx.intraRoundOffset !== undefined) { printInfo(` - intraRoundOffset: ${tx.intraRoundOffset}`); } printInfo('');
// Display payment-specific fields if (tx.paymentTransaction) { printInfo('Payment transaction details:'); printInfo(` - receiver: ${shortenAddress(tx.paymentTransaction.receiver)}`); printInfo(` - amount: ${formatMicroAlgo(tx.paymentTransaction.amount)}`); if (tx.paymentTransaction.closeRemainderTo) { printInfo( ` - closeRemainderTo: ${shortenAddress(tx.paymentTransaction.closeRemainderTo)}`, ); } if (tx.paymentTransaction.closeAmount !== undefined) { printInfo(` - closeAmount: ${formatMicroAlgo(tx.paymentTransaction.closeAmount)}`); } }
printInfo(''); printInfo(`Query performed at round: ${txnResult.currentRound}`); } catch (error) { printError( `lookupTransactionById failed: ${error instanceof Error ? error.message : String(error)}`, ); }
// ========================================================================= // Step 4: Lookup asset transfer transaction by ID // ========================================================================= printStep(4, 'Looking up asset transfer transaction by ID');
try { const txnResult = await indexer.lookupTransactionById(assetTransferTxId); const tx = txnResult.transaction;
printSuccess(`Transaction found!`); printInfo(''); printInfo('Common transaction fields:'); printInfo(` - id: ${tx.id}`); printInfo(` - txType: ${tx.txType}`); printInfo(` - sender: ${shortenAddress(tx.sender)}`); printInfo(` - fee: ${formatMicroAlgo(tx.fee)}`); printInfo(` - firstValid: ${tx.firstValid}`); printInfo(` - lastValid: ${tx.lastValid}`); printInfo('');
printInfo('Confirmation info:'); if (tx.confirmedRound !== undefined) { printInfo(` - confirmedRound: ${tx.confirmedRound}`); } if (tx.roundTime !== undefined) { const date = new Date(tx.roundTime * 1000); printInfo(` - roundTime: ${date.toISOString()} (Unix: ${tx.roundTime})`); } if (tx.intraRoundOffset !== undefined) { printInfo(` - intraRoundOffset: ${tx.intraRoundOffset}`); } printInfo('');
// Display asset transfer-specific fields if (tx.assetTransferTransaction) { printInfo('Asset transfer transaction details:'); printInfo(` - assetId: ${tx.assetTransferTransaction.assetId}`); printInfo(` - amount: ${tx.assetTransferTransaction.amount}`); printInfo(` - receiver: ${shortenAddress(tx.assetTransferTransaction.receiver)}`); if (tx.assetTransferTransaction.sender) { printInfo(` - sender (clawback): ${shortenAddress(tx.assetTransferTransaction.sender)}`); } if (tx.assetTransferTransaction.closeTo) { printInfo(` - closeTo: ${shortenAddress(tx.assetTransferTransaction.closeTo)}`); } if (tx.assetTransferTransaction.closeAmount !== undefined) { printInfo(` - closeAmount: ${tx.assetTransferTransaction.closeAmount}`); } }
printInfo(''); printInfo(`Query performed at round: ${txnResult.currentRound}`); } catch (error) { printError( `lookupTransactionById failed: ${error instanceof Error ? error.message : String(error)}`, ); }
// ========================================================================= // Step 5: Handle transaction not found case // ========================================================================= printStep(5, 'Handling transaction not found case');
try { // Use a fake transaction ID that doesn't exist const fakeTxId = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1234'; printInfo(`Attempting to lookup non-existent transaction: ${shortenAddress(fakeTxId, 8, 6)}`);
await indexer.lookupTransactionById(fakeTxId);
// If we get here, the transaction was somehow found (shouldn't happen) printInfo('Transaction was unexpectedly found'); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if ( errorMessage.toLowerCase().includes('not found') || errorMessage.toLowerCase().includes('no transactions') ) { printSuccess('Transaction not found - error handled correctly'); printInfo(` Error message: ${errorMessage}`); } else { printError(`Unexpected error: ${errorMessage}`); } }
// ========================================================================= // Step 6: Display additional transaction fields (if available) // ========================================================================= printStep(6, 'Displaying additional transaction fields');
try { const txnResult = await indexer.lookupTransactionById(paymentTxId); const tx = txnResult.transaction;
printInfo('Additional fields (if present):');
if (tx.genesisId) { printInfo(` - genesisId: ${tx.genesisId}`); }
if (tx.genesisHash) { const hashHex = Buffer.from(tx.genesisHash).toString('base64'); printInfo(` - genesisHash: ${hashHex.substring(0, 20)}...`); }
if (tx.group) { const groupHex = Buffer.from(tx.group).toString('base64'); printInfo(` - group: ${groupHex}`); }
if (tx.note) { const noteText = new TextDecoder().decode(tx.note); printInfo(` - note: ${noteText || '(empty)'}`); }
if (tx.lease) { const leaseHex = Buffer.from(tx.lease).toString('base64'); printInfo(` - lease: ${leaseHex}`); }
if (tx.rekeyTo) { printInfo(` - rekeyTo: ${tx.rekeyTo}`); }
if (tx.senderRewards !== undefined) { printInfo(` - senderRewards: ${formatMicroAlgo(tx.senderRewards)}`); }
if (tx.receiverRewards !== undefined) { printInfo(` - receiverRewards: ${formatMicroAlgo(tx.receiverRewards)}`); }
if (tx.closeRewards !== undefined) { printInfo(` - closeRewards: ${formatMicroAlgo(tx.closeRewards)}`); }
if (tx.closingAmount !== undefined) { printInfo(` - closingAmount: ${formatMicroAlgo(tx.closingAmount)}`); }
if (tx.authAddr) { printInfo(` - authAddr: ${tx.authAddr}`); }
if (tx.signature) { printInfo(` - signature: (present)`); if (tx.signature.sig) { printInfo(` - type: single signature`); } if (tx.signature.multisig) { printInfo(` - type: multisig`); } if (tx.signature.logicsig) { printInfo(` - type: logic signature`); } }
// Check for created assets or applications if (tx.createdAssetId !== undefined) { printInfo(` - createdAssetId: ${tx.createdAssetId}`); } if (tx.createdAppId !== undefined) { printInfo(` - createdAppId: ${tx.createdAppId}`); }
// Inner transactions (for app calls) if (tx.innerTxns && tx.innerTxns.length > 0) { printInfo(` - innerTxns: ${tx.innerTxns.length} inner transaction(s)`); }
// Logs (for app calls) if (tx.logs && tx.logs.length > 0) { printInfo(` - logs: ${tx.logs.length} log entry(ies)`); }
// State deltas (for app calls) if (tx.globalStateDelta) { printInfo(` - globalStateDelta: (present)`); } if (tx.localStateDelta && tx.localStateDelta.length > 0) { printInfo(` - localStateDelta: ${tx.localStateDelta.length} account(s) affected`); } } catch (error) { printError( `Failed to display additional fields: ${error instanceof Error ? error.message : String(error)}`, ); }
// ========================================================================= // Summary // ========================================================================= printHeader('Summary'); printInfo('This example demonstrated:'); printInfo(' 1. lookupTransactionById(txId) - Get full transaction details by ID'); printInfo( ' 2. Displaying common transaction fields: id, txType, sender, fee, firstValid, lastValid', ); printInfo(' 3. Displaying confirmation info: confirmedRound, roundTime, intraRoundOffset'); printInfo(' 4. Displaying payment-specific fields: receiver, amount, closeRemainderTo'); printInfo(' 5. Displaying asset transfer-specific fields: assetId, amount, receiver'); printInfo(' 6. Handling transaction not found errors'); printInfo(' 7. Displaying additional fields: genesisId, note, signature, etc.'); printInfo(''); printInfo('TransactionResponse structure:'); printInfo(' - transaction: The full Transaction object'); printInfo(' - currentRound: Round at which the results were computed'); printInfo(''); printInfo('Key Transaction fields:'); printInfo(' - id: Transaction ID (string)'); printInfo(' - txType: Transaction type (pay, keyreg, acfg, axfer, afrz, appl, stpf, hb)'); printInfo(' - sender: Sender address (string)'); printInfo(' - fee: Transaction fee in microAlgos (bigint)'); printInfo(' - firstValid: First valid round (bigint)'); printInfo(' - lastValid: Last valid round (bigint)'); printInfo(' - confirmedRound: Round when confirmed (bigint, optional)'); printInfo(' - roundTime: Unix timestamp when confirmed (number, optional)'); printInfo(' - intraRoundOffset: Position within the round (number, optional)'); printInfo(''); printInfo('Type-specific fields:'); printInfo(' - paymentTransaction: { receiver, amount, closeRemainderTo, closeAmount }'); printInfo( ' - assetTransferTransaction: { assetId, amount, receiver, sender, closeTo, closeAmount }', ); printInfo(' - assetConfigTransaction: { assetId, params }'); printInfo(' - applicationTransaction: { applicationId, onComplete, accounts, etc. }');}
main().catch(error => { console.error('Fatal error:', error); process.exit(1);});