Send Payment
Description
Section titled “Description”This example demonstrates how to send ALGO payment transactions:
- algorand.send.payment() with basic parameters (sender, receiver, amount)
- Using AlgoAmount for the amount parameter
- Payment with note field
- Payment with closeRemainderTo to close account and send remaining balance
- Understanding the SendSingleTransactionResult return value
- Displaying transaction ID and confirmed round
- Verifying balances before and after payment
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 algorand_client/06-send-payment.ts/** * Example: Send Payment * * This example demonstrates how to send ALGO payment transactions: * - algorand.send.payment() with basic parameters (sender, receiver, amount) * - Using AlgoAmount for the amount parameter * - Payment with note field * - Payment with closeRemainderTo to close account and send remaining balance * - Understanding the SendSingleTransactionResult return value * - Displaying transaction ID and confirmed round * - Verifying balances before and after payment * * Prerequisites: * - LocalNet running (via `algokit localnet start`) */
import { AlgorandClient, algo, microAlgo } from '@algorandfoundation/algokit-utils';import { formatAlgo, printError, printHeader, printInfo, printStep, printSuccess, shortenAddress,} from '../shared/utils.js';
async function main() { printHeader('Send Payment Example');
// Initialize client and verify LocalNet is running const algorand = AlgorandClient.defaultLocalNet();
try { await algorand.client.algod.status(); printSuccess('Connected to LocalNet'); } catch (error) { printError( `Failed to connect to LocalNet: ${error instanceof Error ? error.message : String(error)}`, ); printInfo('Make sure LocalNet is running (e.g., algokit localnet start)'); return; }
// Step 1: Create and fund test accounts printStep(1, 'Create and fund test accounts using account manager'); printInfo('Creating test accounts and funding them from the LocalNet dispenser');
const sender = algorand.account.random(); const receiver = algorand.account.random(); const closeToAccount = algorand.account.random();
printInfo(`\nCreated accounts:`); printInfo(` Sender: ${shortenAddress(sender.addr.toString())}`); printInfo(` Receiver: ${shortenAddress(receiver.addr.toString())}`); printInfo(` CloseToAccount: ${shortenAddress(closeToAccount.addr.toString())}`);
// Fund the sender account using ensureFundedFromEnvironment const fundResult = await algorand.account.ensureFundedFromEnvironment(sender.addr, algo(20)); if (fundResult) { printInfo(`\nFunded sender with: ${formatAlgo(fundResult.amountFunded)}`); }
// Also fund closeToAccount so it exists on the network await algorand.account.ensureFundedFromEnvironment(closeToAccount.addr, algo(1));
// Get initial balances const senderInitialInfo = await algorand.account.getInformation(sender.addr); const receiverInitialInfo = await algorand.account.getInformation(receiver.addr);
printInfo(`\nInitial balances:`); printInfo(` Sender: ${formatAlgo(senderInitialInfo.balance)}`); printInfo(` Receiver: ${formatAlgo(receiverInitialInfo.balance)}`);
printSuccess('Created and funded test accounts');
// Step 2: Basic payment with algorand.send.payment() printStep(2, 'Basic payment with algorand.send.payment()'); printInfo('Sending a simple ALGO payment with sender, receiver, and amount');
const basicPaymentResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: algo(5), // Using AlgoAmount helper });
printInfo(`\nBasic payment sent:`); printInfo(` From: ${shortenAddress(sender.addr.toString())}`); printInfo(` To: ${shortenAddress(receiver.addr.toString())}`); printInfo(` Amount: 5 ALGO`);
// Examine the SendSingleTransactionResult return value printInfo(`\nSendSingleTransactionResult properties:`); printInfo(` txIds[0]: ${basicPaymentResult.txIds[0]}`); printInfo(` confirmation.confirmedRound: ${basicPaymentResult.confirmation.confirmedRound}`); printInfo(` transaction.txId(): ${basicPaymentResult.transaction.txId()}`); printInfo(` groupId: ${basicPaymentResult.groupId ?? 'undefined (single transaction)'}`); printInfo(` transactions.length: ${basicPaymentResult.transactions.length}`); printInfo(` confirmations.length: ${basicPaymentResult.confirmations.length}`);
printSuccess('Basic payment completed');
// Step 3: Using AlgoAmount for the amount parameter printStep(3, 'Using AlgoAmount for the amount parameter'); printInfo('AlgoAmount provides type-safe handling of ALGO and microALGO values');
// Different ways to specify amounts const amount1 = algo(1); // 1 ALGO using helper function const amount2 = microAlgo(500_000); // 0.5 ALGO in microALGO
printInfo(`\nDifferent amount specifications:`); printInfo(` algo(1) = ${formatAlgo(amount1)} (${amount1.microAlgo} µALGO)`); printInfo(` microAlgo(500_000) = ${formatAlgo(amount2)} (${amount2.microAlgo} µALGO)`);
// Send payment with microAlgo amount const microAlgoPaymentResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: microAlgo(250_000), // 0.25 ALGO });
printInfo(`\nPayment with microAlgo amount:`); printInfo(` Amount: ${formatAlgo(microAlgo(250_000))} (250,000 µALGO)`); printInfo(` Transaction ID: ${microAlgoPaymentResult.txIds[0]}`);
printSuccess('Demonstrated AlgoAmount usage');
// Step 4: Payment with note field printStep(4, 'Payment with note field'); printInfo('Adding arbitrary data to a payment using the note field'); printInfo('Notes can be strings, byte arrays, or structured data (JSON)');
// String note const stringNoteResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: algo(0.1), note: 'Payment for services rendered', });
printInfo(`\nPayment with string note:`); printInfo(` Note: "Payment for services rendered"`); printInfo(` Transaction ID: ${stringNoteResult.txIds[0]}`);
// JSON note (useful for structured data) const jsonNote = JSON.stringify({ type: 'invoice', id: '12345', timestamp: new Date().toISOString(), });
const jsonNoteResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: algo(0.1), note: jsonNote, });
printInfo(`\nPayment with JSON note:`); printInfo(` Note: ${jsonNote}`); printInfo(` Transaction ID: ${jsonNoteResult.txIds[0]}`);
// Byte array note const byteNote = new TextEncoder().encode('Binary data note');
const byteNoteResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: algo(0.1), note: byteNote, });
printInfo(`\nPayment with byte array note:`); printInfo(` Note: Uint8Array(${byteNote.length}) - "Binary data note"`); printInfo(` Transaction ID: ${byteNoteResult.txIds[0]}`);
printSuccess('Demonstrated payment with notes');
// Step 5: Verify balances before and after payment printStep(5, 'Verify balances before and after payment using getInformation()'); printInfo('Using algorand.account.getInformation() to check account balances');
// Get current balances const senderBeforeInfo = await algorand.account.getInformation(sender.addr); const receiverBeforeInfo = await algorand.account.getInformation(receiver.addr);
printInfo(`\nBalances before payment:`); printInfo(` Sender: ${formatAlgo(senderBeforeInfo.balance)}`); printInfo(` Receiver: ${formatAlgo(receiverBeforeInfo.balance)}`);
// Send a precise amount const precisAmount = algo(2); await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: precisAmount, });
// Get balances after payment const senderAfterInfo = await algorand.account.getInformation(sender.addr); const receiverAfterInfo = await algorand.account.getInformation(receiver.addr);
printInfo(`\nBalances after sending ${formatAlgo(precisAmount)}:`); printInfo(` Sender: ${formatAlgo(senderAfterInfo.balance)}`); printInfo(` Receiver: ${formatAlgo(receiverAfterInfo.balance)}`);
// Calculate the difference (includes transaction fee) const senderDiff = senderBeforeInfo.balance.microAlgo - senderAfterInfo.balance.microAlgo; const receiverDiff = receiverAfterInfo.balance.microAlgo - receiverBeforeInfo.balance.microAlgo;
printInfo(`\nBalance changes:`); printInfo(` Sender lost: ${formatAlgo(senderDiff)} (amount + fee)`); printInfo(` Receiver gained: ${formatAlgo(receiverDiff)}`); printInfo(` Transaction fee: ${formatAlgo(senderDiff - receiverDiff)}`);
printSuccess('Verified balance changes');
// Step 6: Demonstrate closeRemainderTo to close account printStep(6, 'Demonstrate closeRemainderTo to close account and send remaining balance'); printInfo('closeRemainderTo closes the sender account and sends ALL remaining balance'); printInfo('WARNING: This permanently closes the account - use with caution!');
// Create a new account specifically for closing const accountToClose = algorand.account.random(); await algorand.account.ensureFundedFromEnvironment(accountToClose.addr, algo(5));
const accountToCloseInitialInfo = await algorand.account.getInformation(accountToClose.addr); const closeToInitialInfo = await algorand.account.getInformation(closeToAccount.addr);
printInfo(`\nAccount to close: ${shortenAddress(accountToClose.addr.toString())}`); printInfo(` Initial balance: ${formatAlgo(accountToCloseInitialInfo.balance)}`); printInfo(`\nClose remainder to: ${shortenAddress(closeToAccount.addr.toString())}`); printInfo(` Initial balance: ${formatAlgo(closeToInitialInfo.balance)}`);
// Send a payment with closeRemainderTo // This will: // 1. Send the specified amount to receiver // 2. Send ALL remaining balance to closeRemainderTo address // 3. Close the sender account const closeResult = await algorand.send.payment({ sender: accountToClose.addr, receiver: receiver.addr, // Receiver gets the explicit amount amount: algo(1), // Explicit amount to receiver closeRemainderTo: closeToAccount.addr, // Remainder goes here, account closes });
printInfo(`\nClose account transaction:`); printInfo(` Transaction ID: ${closeResult.txIds[0]}`); printInfo(` Confirmed round: ${closeResult.confirmation.confirmedRound}`); printInfo(` Explicit amount to receiver: ${formatAlgo(algo(1))}`);
// Verify the close operation const accountToCloseFinalInfo = await algorand.account.getInformation(accountToClose.addr); const receiverFinalInfo = await algorand.account.getInformation(receiver.addr); const closeToFinalInfo = await algorand.account.getInformation(closeToAccount.addr);
printInfo(`\nAfter closing:`); printInfo( ` Closed account balance: ${formatAlgo(accountToCloseFinalInfo.balance)} (should be 0)`, ); printInfo( ` Receiver gained: ${formatAlgo(receiverFinalInfo.balance.microAlgo - receiverBeforeInfo.balance.microAlgo)}`, ); printInfo(` CloseToAccount balance: ${formatAlgo(closeToFinalInfo.balance)}`); printInfo( ` CloseToAccount gained: ${formatAlgo(closeToFinalInfo.balance.microAlgo - closeToInitialInfo.balance.microAlgo)}`, );
printSuccess('Demonstrated closeRemainderTo');
// Step 7: Waiting for confirmation printStep(7, 'Understanding transaction confirmation'); printInfo('algorand.send.payment() automatically waits for confirmation'); printInfo('The result includes confirmation details from the network');
const confirmationResult = await algorand.send.payment({ sender: sender.addr, receiver: receiver.addr, amount: algo(0.5), });
printInfo(`\nTransaction confirmation details:`); printInfo(` Transaction ID: ${confirmationResult.txIds[0]}`); printInfo(` Confirmed round: ${confirmationResult.confirmation.confirmedRound}`); printInfo(` Pool error: ${confirmationResult.confirmation.poolError ?? 'none'}`);
// Access the Transaction object printInfo(`\nTransaction object details:`); printInfo(` txId(): ${confirmationResult.transaction.txId()}`); printInfo(` type: ${confirmationResult.transaction.type}`); printInfo(` firstValid: ${confirmationResult.transaction.firstValid}`); printInfo(` lastValid: ${confirmationResult.transaction.lastValid}`); printInfo(` fee: ${confirmationResult.transaction.fee} µALGO`);
printSuccess('Demonstrated transaction confirmation');
// Step 8: Summary of SendSingleTransactionResult printStep(8, 'Summary - SendSingleTransactionResult properties'); printInfo('When you call algorand.send.payment(), you get a SendSingleTransactionResult:'); printInfo(''); printInfo('Primary transaction properties:'); printInfo(' txIds[0]: string - The transaction ID for single transactions'); printInfo(' transaction: Transaction - The Transaction object'); printInfo(' confirmation: PendingTransactionResponse - Confirmation details'); printInfo(''); printInfo('Group properties (also present for single transactions):'); printInfo(' groupId: string | undefined - The group ID if part of a group'); printInfo(' txIds: string[] - Array of transaction IDs'); printInfo(' transactions: Transaction[] - Array of Transaction objects'); printInfo(' confirmations: PendingTransactionResponse[] - Array of confirmations'); printInfo(''); printInfo('Useful confirmation properties:'); printInfo(' confirmation.confirmedRound - The round the transaction was confirmed'); printInfo(' confirmation.poolError - Any error message from the pool'); printInfo(' confirmation.closingAmount - Amount sent to closeRemainderTo (if used)'); printInfo(''); printInfo('Payment parameters:'); printInfo(' sender: Address - Who is sending the payment'); printInfo(' receiver: Address - Who receives the payment'); printInfo(' amount: AlgoAmount - How much to send'); printInfo(' note?: string | Uint8Array - Optional note data'); printInfo(' closeRemainderTo?: Address - Close account and send remainder here');
// Final balance summary printStep(9, 'Final balance summary');
const finalSenderInfo = await algorand.account.getInformation(sender.addr); const finalReceiverInfo = await algorand.account.getInformation(receiver.addr);
printInfo(`\nFinal balances:`); printInfo( ` Sender: ${formatAlgo(finalSenderInfo.balance)} (started with ${formatAlgo(senderInitialInfo.balance)})`, ); printInfo( ` Receiver: ${formatAlgo(finalReceiverInfo.balance)} (started with ${formatAlgo(receiverInitialInfo.balance)})`, );
printSuccess('Send Payment example completed!');}
main().catch(error => { printError(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`); process.exit(1);});Other examples in Algorand Client
Section titled “Other examples in Algorand Client”- Client Instantiation
- AlgoAmount Utility
- Signer Configuration
- Suggested Params Configuration
- Account Manager
- Send Payment
- Send Asset Operations
- Send Application Operations
- Create Transaction (Unsigned Transactions)
- Transaction Composer (Atomic Transaction Groups)
- Asset Manager
- App Manager
- App Deployer
- Client Manager
- Error Transformers
- Transaction Leases