Skip to content

AlgoAmount Utility

← Back to Algorand Client

This example demonstrates how to use the AlgoAmount utility class to work with ALGO and microALGO amounts safely, avoiding floating point precision issues. Topics covered:

  • Creating AlgoAmount using static factory methods
  • Accessing values in ALGO and microALGO
  • String formatting
  • Arithmetic operations (addition, subtraction)
  • Comparison operations
  • Using AlgoAmount with payment transactions
  • Avoiding floating point precision issues
  • No LocalNet required

From the repository root:

Terminal window
cd examples
npm run example algorand_client/02-algo-amount.ts

View source on GitHub

02-algo-amount.ts
/**
* Example: AlgoAmount Utility
*
* This example demonstrates how to use the AlgoAmount utility class to work
* with ALGO and microALGO amounts safely, avoiding floating point precision issues.
*
* Topics covered:
* - Creating AlgoAmount using static factory methods
* - Accessing values in ALGO and microALGO
* - String formatting
* - Arithmetic operations (addition, subtraction)
* - Comparison operations
* - Using AlgoAmount with payment transactions
* - Avoiding floating point precision issues
*
* Prerequisites:
* - No LocalNet required
*/
import { algo, ALGORAND_MIN_TX_FEE, AlgorandClient, algos, microAlgo, microAlgos, transactionFees } from '@algorandfoundation/algokit-utils'
import { AlgoAmount } from '@algorandfoundation/algokit-utils/types/amount'
import { printError, printHeader, printInfo, printStep, printSuccess, shortenAddress } from '../shared/utils.js'
async function main() {
printHeader('AlgoAmount Utility Example')
// Step 1: Creating AlgoAmount using static factory methods
printStep(1, 'Creating AlgoAmount using static factory methods')
printInfo('AlgoAmount provides four static factory methods:')
printInfo(' - AlgoAmount.Algo(amount) - Create from ALGO value')
printInfo(' - AlgoAmount.Algos(amount) - Alias for Algo()')
printInfo(' - AlgoAmount.MicroAlgo(amount) - Create from microALGO value')
printInfo(' - AlgoAmount.MicroAlgos(amount) - Alias for MicroAlgo()')
// Create using AlgoAmount.Algo()
const oneAndHalfAlgo = AlgoAmount.Algo(1.5)
printInfo(`\nAlgoAmount.Algo(1.5): ${oneAndHalfAlgo.algo} ALGO = ${oneAndHalfAlgo.microAlgo} µALGO`)
// Create using AlgoAmount.Algos() - alias
const twoAlgos = AlgoAmount.Algos(2)
printInfo(`AlgoAmount.Algos(2): ${twoAlgos.algo} ALGO = ${twoAlgos.microAlgo} µALGO`)
// Create using AlgoAmount.MicroAlgo()
const fiftyThousandMicroAlgo = AlgoAmount.MicroAlgo(50_000)
printInfo(`AlgoAmount.MicroAlgo(50000): ${fiftyThousandMicroAlgo.algo} ALGO = ${fiftyThousandMicroAlgo.microAlgo} µALGO`)
// Create using AlgoAmount.MicroAlgos() - alias
const hundredThousandMicroAlgo = AlgoAmount.MicroAlgos(100_000)
printInfo(`AlgoAmount.MicroAlgos(100000): ${hundredThousandMicroAlgo.algo} ALGO = ${hundredThousandMicroAlgo.microAlgo} µALGO`)
printSuccess('Created AlgoAmount instances using all factory methods')
// Step 2: Using helper functions
printStep(2, 'Using convenience helper functions')
printInfo('The library exports helper functions for cleaner syntax:')
printInfo(' - algo(amount) - Equivalent to AlgoAmount.Algo()')
printInfo(' - algos(amount) - Equivalent to AlgoAmount.Algos()')
printInfo(' - microAlgo(amount) - Equivalent to AlgoAmount.MicroAlgo()')
printInfo(' - microAlgos(amount) - Equivalent to AlgoAmount.MicroAlgos()')
const threeAlgo = algo(3)
printInfo(`\nalgo(3): ${threeAlgo.algo} ALGO = ${threeAlgo.microAlgo} µALGO`)
const fiveAlgos = algos(5)
printInfo(`algos(5): ${fiveAlgos.algo} ALGO = ${fiveAlgos.microAlgo} µALGO`)
const tenMicroAlgo = microAlgo(10)
printInfo(`microAlgo(10): ${tenMicroAlgo.algo} ALGO = ${tenMicroAlgo.microAlgo} µALGO`)
const twentyMicroAlgos = microAlgos(20)
printInfo(`microAlgos(20): ${twentyMicroAlgos.algo} ALGO = ${twentyMicroAlgos.microAlgo} µALGO`)
// Transaction fees helper
const threeTransactionFees = transactionFees(3)
printInfo(`\ntransactionFees(3): ${threeTransactionFees.microAlgo} µALGO (covers 3 standard transactions)`)
printInfo(`ALGORAND_MIN_TX_FEE: ${ALGORAND_MIN_TX_FEE.microAlgo} µALGO (minimum transaction fee)`)
printSuccess('Demonstrated convenience helper functions')
// Step 3: Accessing values in ALGO and microALGO
printStep(3, 'Accessing values using .algo and .microAlgo properties')
printInfo('AlgoAmount provides getter properties to access the value:')
printInfo(' - .algo / .algos - Get value in ALGO (as number)')
printInfo(' - .microAlgo / .microAlgos - Get value in µALGO (as bigint)')
const amount = AlgoAmount.Algo(2.5)
printInfo(`\nFor amount = AlgoAmount.Algo(2.5):`)
printInfo(` .algo: ${amount.algo} (type: ${typeof amount.algo})`)
printInfo(` .algos: ${amount.algos} (alias for .algo)`)
printInfo(` .microAlgo: ${amount.microAlgo} (type: ${typeof amount.microAlgo})`)
printInfo(` .microAlgos: ${amount.microAlgos} (alias for .microAlgo)`)
printSuccess('Accessed values using all getter properties')
// Step 4: String formatting with toString()
printStep(4, 'String formatting with toString()')
printInfo('The toString() method formats the amount for human-readable display')
const formattedAmount = AlgoAmount.Algo(1.234567)
printInfo(`\nAlgoAmount.Algo(1.234567).toString(): "${formattedAmount.toString()}"`)
const largeAmount = AlgoAmount.MicroAlgo(1_234_567_890)
printInfo(`AlgoAmount.MicroAlgo(1234567890).toString(): "${largeAmount.toString()}"`)
// Custom formatting using properties
printInfo('\nCustom formatting examples:')
printInfo(` ${amount.algo.toFixed(2)} ALGO`)
printInfo(` ${amount.microAlgo.toLocaleString('en-US')} µALGO`)
printSuccess('Demonstrated string formatting')
// Step 5: Arithmetic operations
printStep(5, 'Arithmetic operations (addition, subtraction)')
printInfo('AlgoAmount uses bigint internally for precision.')
printInfo('Arithmetic is done by accessing .microAlgo and creating new AlgoAmount:')
const amountA = AlgoAmount.Algo(5)
const amountB = AlgoAmount.Algo(2.5)
printInfo(`\namountA = AlgoAmount.Algo(5): ${amountA.algo} ALGO`)
printInfo(`amountB = AlgoAmount.Algo(2.5): ${amountB.algo} ALGO`)
// Addition
const sum = AlgoAmount.MicroAlgo(amountA.microAlgo + amountB.microAlgo)
printInfo(`\nAddition: amountA + amountB`)
printInfo(` AlgoAmount.MicroAlgo(${amountA.microAlgo} + ${amountB.microAlgo})`)
printInfo(` = ${sum.algo} ALGO (${sum.microAlgo} µALGO)`)
// Subtraction
const difference = AlgoAmount.MicroAlgo(amountA.microAlgo - amountB.microAlgo)
printInfo(`\nSubtraction: amountA - amountB`)
printInfo(` AlgoAmount.MicroAlgo(${amountA.microAlgo} - ${amountB.microAlgo})`)
printInfo(` = ${difference.algo} ALGO (${difference.microAlgo} µALGO)`)
// Adding transaction fees
const amountWithFee = AlgoAmount.MicroAlgo(amountA.microAlgo + ALGORAND_MIN_TX_FEE.microAlgo)
printInfo(`\nAdding transaction fee:`)
printInfo(` ${amountA.algo} ALGO + ${ALGORAND_MIN_TX_FEE.microAlgo} µALGO fee = ${amountWithFee.algo} ALGO`)
printSuccess('Demonstrated arithmetic operations')
// Step 6: Comparison operations
printStep(6, 'Comparison operations')
printInfo('AlgoAmount implements valueOf() which enables comparison operators')
printInfo('valueOf() returns the microAlgo value as a number')
const small = AlgoAmount.Algo(1)
const medium = AlgoAmount.Algo(5)
const large = AlgoAmount.Algo(10)
const equalToMedium = AlgoAmount.MicroAlgo(5_000_000)
printInfo(`\nsmall = 1 ALGO, medium = 5 ALGO, large = 10 ALGO, equalToMedium = 5_000_000 µALGO`)
printInfo(`\nComparison results:`)
printInfo(` small < medium: ${small < medium}`)
printInfo(` medium < large: ${medium < large}`)
printInfo(` large > small: ${large > small}`)
printInfo(` medium >= equalToMedium: ${medium >= equalToMedium}`)
printInfo(` medium <= equalToMedium: ${medium <= equalToMedium}`)
// Direct microAlgo comparison for exact equality (recommended)
printInfo(`\nFor exact equality, compare microAlgo values (bigint):`)
printInfo(` medium.microAlgo === equalToMedium.microAlgo: ${medium.microAlgo === equalToMedium.microAlgo}`)
printSuccess('Demonstrated comparison operations')
// Step 7: Avoiding floating point precision issues
printStep(7, 'Avoiding floating point precision issues')
printInfo('JavaScript floating point arithmetic has precision issues.')
printInfo('AlgoAmount avoids this by using bigint internally.')
// Classic floating point problem
const floatResult = 0.1 + 0.2
printInfo(`\nClassic floating point problem:`)
printInfo(` 0.1 + 0.2 = ${floatResult} (not 0.3!)`)
printInfo(` 0.1 + 0.2 === 0.3: ${floatResult === 0.3}`)
// AlgoAmount handles this correctly
const algoA = AlgoAmount.Algo(0.1)
const algoB = AlgoAmount.Algo(0.2)
const algoSum = AlgoAmount.MicroAlgo(algoA.microAlgo + algoB.microAlgo)
printInfo(`\nUsing AlgoAmount:`)
printInfo(` AlgoAmount.Algo(0.1).microAlgo = ${algoA.microAlgo}`)
printInfo(` AlgoAmount.Algo(0.2).microAlgo = ${algoB.microAlgo}`)
printInfo(` Sum in microAlgo: ${algoA.microAlgo} + ${algoB.microAlgo} = ${algoSum.microAlgo}`)
printInfo(` Sum in Algo: ${algoSum.algo}`)
printInfo(` ${algoSum.microAlgo} === ${AlgoAmount.Algo(0.3).microAlgo}: ${algoSum.microAlgo === AlgoAmount.Algo(0.3).microAlgo}`)
// Another precision example
printInfo(`\nAnother example with 1.23456789 ALGO:`)
const preciseAmount = AlgoAmount.Algo(1.23456789)
printInfo(` AlgoAmount.Algo(1.23456789).microAlgo = ${preciseAmount.microAlgo}`)
printInfo(` Stored as: 1,234,568 µALGO (rounded to 6 decimal places)`)
printSuccess('Demonstrated floating point precision handling')
// Step 8: Using AlgoAmount with payment transactions
printStep(8, 'Using AlgoAmount with payment transactions')
printInfo('AlgoAmount integrates seamlessly with AlgorandClient payment methods')
printInfo('This step requires LocalNet to be running')
try {
const algorand = AlgorandClient.defaultLocalNet()
// Verify connection
await algorand.client.algod.status()
// Get accounts
const dispenser = await algorand.account.dispenserFromEnvironment()
const receiver = algorand.account.random()
printInfo(`\nSender (dispenser): ${shortenAddress(dispenser.addr.toString())}`)
printInfo(`Receiver (random): ${shortenAddress(receiver.addr.toString())}`)
// Get initial balance
const initialBalance = (await algorand.account.getInformation(dispenser.addr)).balance
printInfo(`\nInitial sender balance: ${initialBalance.algo} ALGO`)
// Send payment using AlgoAmount
const paymentAmount = AlgoAmount.Algo(1.5)
printInfo(`\nSending ${paymentAmount.algo} ALGO (${paymentAmount.microAlgo} µALGO)...`)
const result = await algorand.send.payment({
sender: dispenser.addr,
receiver: receiver.addr,
amount: paymentAmount,
})
printInfo(`Transaction ID: ${result.txIds[0]}`)
printInfo(`Confirmed in round: ${result.confirmation.confirmedRound}`)
// Check balances after
const senderBalance = (await algorand.account.getInformation(dispenser.addr)).balance
const receiverBalance = (await algorand.account.getInformation(receiver.addr)).balance
printInfo(`\nFinal balances:`)
printInfo(` Sender: ${senderBalance.algo} ALGO`)
printInfo(` Receiver: ${receiverBalance.algo} ALGO (${receiverBalance.microAlgo} µALGO)`)
// Verify the receiver got exactly the right amount
printInfo(`\nVerification:`)
printInfo(` Expected receiver balance: ${paymentAmount.microAlgo} µALGO`)
printInfo(` Actual receiver balance: ${receiverBalance.microAlgo} µALGO`)
printInfo(` Match: ${receiverBalance.microAlgo === paymentAmount.microAlgo}`)
printSuccess('Payment transaction completed successfully!')
} catch (error) {
printError(`Failed to run payment example: ${error instanceof Error ? error.message : String(error)}`)
printInfo('Make sure LocalNet is running (e.g., algokit localnet start)')
printInfo('This step demonstrates AlgoAmount integration with transactions')
}
// Step 9: Summary
printStep(9, 'Summary')
printInfo('AlgoAmount is a wrapper class for safe ALGO/µALGO handling:')
printInfo('')
printInfo('Factory methods:')
printInfo(' - AlgoAmount.Algo(n) / AlgoAmount.Algos(n) - From ALGO')
printInfo(' - AlgoAmount.MicroAlgo(n) / AlgoAmount.MicroAlgos(n) - From µALGO')
printInfo(' - algo(n), algos(n), microAlgo(n), microAlgos(n) - Helper functions')
printInfo('')
printInfo('Properties:')
printInfo(' - .algo / .algos - Get value in ALGO (number)')
printInfo(' - .microAlgo / .microAlgos - Get value in µALGO (bigint)')
printInfo('')
printInfo('Operations:')
printInfo(' - Arithmetic: Use .microAlgo + wrap result in AlgoAmount.MicroAlgo()')
printInfo(' - Comparison: <, >, <=, >= work directly; use .microAlgo for ===')
printInfo(' - Formatting: .toString() or access properties for custom format')
printInfo('')
printInfo('Best practices:')
printInfo(' - Always use AlgoAmount for financial calculations')
printInfo(' - Perform arithmetic on .microAlgo (bigint) to avoid precision loss')
printInfo(' - Use helper functions (algo, microAlgo) for cleaner code')
printInfo(' - Use transactionFees(n) when calculating fees for multiple transactions')
printSuccess('AlgoAmount Utility example completed!')
}
main().catch((error) => {
printError(`Unhandled error: ${error instanceof Error ? error.message : String(error)}`)
process.exit(1)
})