ABI Address Type
Description
Section titled “Description”This example demonstrates how to encode and decode Algorand addresses using ABIAddressType:
- Encoding address strings (base32 format) to 32 bytes
- Encoding raw 32-byte public key (Uint8Array)
- Decoding bytes back to address string
- Verifying address encoding is exactly 32 bytes (no length prefix)
- Understanding relationship between Algorand address and public key bytes Algorand addresses are 58 characters in base32 encoding, which includes:
- 32 bytes of public key
- 4 bytes of checksum (computed from public key) The ABI encoding is just the raw 32-byte public key without checksum.
Prerequisites
Section titled “Prerequisites”- No LocalNet required
Run This Example
Section titled “Run This Example”From the repository root:
cd examplesnpm run example abi/03-address-type.ts/** * Example: ABI Address Type * * This example demonstrates how to encode and decode Algorand addresses using ABIAddressType: * - Encoding address strings (base32 format) to 32 bytes * - Encoding raw 32-byte public key (Uint8Array) * - Decoding bytes back to address string * - Verifying address encoding is exactly 32 bytes (no length prefix) * - Understanding relationship between Algorand address and public key bytes * * Algorand addresses are 58 characters in base32 encoding, which includes: * - 32 bytes of public key * - 4 bytes of checksum (computed from public key) * * The ABI encoding is just the raw 32-byte public key without checksum. * * Prerequisites: * - No LocalNet required */
import { Address, ALGORAND_ZERO_ADDRESS_STRING } from '@algorandfoundation/algokit-utils'import { ABIAddressType } from '@algorandfoundation/algokit-utils/abi'import { formatBytes, formatHex, printHeader, printInfo, printStep, printSuccess } from '../shared/utils.js'
function main() { printHeader('ABI Address Type Example')
// Step 1: Create ABIAddressType and inspect properties printStep(1, 'ABIAddressType Properties')
const addressType = new ABIAddressType()
printInfo(`Type name: ${addressType.toString()}`) printInfo(`Byte length: ${addressType.byteLen()} bytes`) printInfo(`Is dynamic: ${addressType.isDynamic()}`)
// Step 2: Encode a base32 address string to bytes printStep(2, 'Encode Address String (Base32) to Bytes')
// Example address - the zero address const zeroAddressString = ALGORAND_ZERO_ADDRESS_STRING printInfo(`Zero address string: ${zeroAddressString}`) printInfo(`Address string length: ${zeroAddressString.length} characters`)
const zeroEncoded = addressType.encode(zeroAddressString) printInfo(`Encoded bytes: ${formatHex(zeroEncoded)}`) printInfo(`Encoded length: ${zeroEncoded.length} bytes (exactly 32, no length prefix)`)
// Verify the zero address encodes to all zeros const allZeros = zeroEncoded.every((byte) => byte === 0) printInfo(`All bytes are zero: ${allZeros}`)
// Step 3: Encode another address string printStep(3, 'Encode a Real Address String')
// Create a sample address from a known public key (32 bytes of incrementing values) const samplePublicKey = new Uint8Array(32) for (let i = 0; i < 32; i++) { samplePublicKey[i] = i }
// Create Address object from public key to get base32 string const sampleAddress = new Address(samplePublicKey) const sampleAddressString = sampleAddress.toString()
printInfo(`Sample address string: ${sampleAddressString}`) printInfo(`Address string length: ${sampleAddressString.length} characters`)
const sampleEncoded = addressType.encode(sampleAddressString) printInfo(`Encoded bytes: ${formatBytes(sampleEncoded, 16)}`) printInfo(`Encoded as hex: ${formatHex(sampleEncoded)}`) printInfo(`Encoded length: ${sampleEncoded.length} bytes`)
// Step 4: Encode from raw 32-byte public key (Uint8Array) printStep(4, 'Encode from Raw 32-Byte Public Key')
// ABIAddressType can also encode directly from a Uint8Array const rawPublicKey = new Uint8Array([ 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, ])
printInfo(`Raw public key: ${formatHex(rawPublicKey)}`)
const encodedFromRaw = addressType.encode(rawPublicKey) printInfo(`Encoded from raw: ${formatHex(encodedFromRaw)}`)
// Verify encoding from raw bytes returns the same bytes const rawBytesMatch = encodedFromRaw.every((byte, index) => byte === rawPublicKey[index]) printInfo(`Raw bytes match encoded: ${rawBytesMatch}`)
// Step 5: Decode bytes back to address string printStep(5, 'Decode Bytes Back to Address String')
// Decode the sample encoded bytes back to address string const decodedSampleAddress = addressType.decode(sampleEncoded) printInfo(`Original address: ${sampleAddressString}`) printInfo(`Decoded address: ${decodedSampleAddress}`) printInfo(`Round-trip verified: ${decodedSampleAddress === sampleAddressString}`)
// Decode zero address const decodedZeroAddress = addressType.decode(zeroEncoded) printInfo(`\nOriginal zero address: ${zeroAddressString}`) printInfo(`Decoded zero address: ${decodedZeroAddress}`) printInfo(`Round-trip verified: ${decodedZeroAddress === zeroAddressString}`)
// Decode the raw public key const decodedFromRawAddress = addressType.decode(encodedFromRaw) printInfo(`\nRaw public key as address: ${decodedFromRawAddress}`)
// Step 6: Relationship between Algorand address and public key bytes printStep(6, 'Address vs Public Key Relationship')
printInfo('Algorand address format:') printInfo(' - Base32 encoded string') printInfo(' - 58 characters long') printInfo(' - Contains: 32-byte public key + 4-byte checksum')
printInfo('\nABI address encoding:') printInfo(' - Just the raw 32-byte public key') printInfo(' - No checksum included') printInfo(' - No length prefix (unlike ABI string type)') printInfo(' - Fixed size, not dynamic')
// Demonstrate using Address class directly printInfo('\nUsing Address class:') const addr = Address.fromString(sampleAddressString) printInfo(` Address.fromString('${sampleAddressString.substring(0, 20)}...')`) printInfo(` .publicKey: ${formatBytes(addr.publicKey, 8)}`) printInfo(` .toString(): ${addr.toString()}`)
// Show that ABIAddressType encoding equals Address.publicKey const publicKeyMatches = addr.publicKey.every((byte, index) => byte === sampleEncoded[index]) printInfo(`\nABI encoding equals Address.publicKey: ${publicKeyMatches}`)
// Step 7: Encoding Address object directly printStep(7, 'Encode Address Object Directly')
// ABIAddressType can also accept Address objects const addressObject = new Address(rawPublicKey) const encodedFromAddressObject = addressType.encode(addressObject)
printInfo(`Address object: ${addressObject.toString()}`) printInfo(`Encoded from Address object: ${formatHex(encodedFromAddressObject)}`)
const addressObjectMatches = encodedFromAddressObject.every((byte, index) => byte === rawPublicKey[index]) printInfo(`Encoding matches raw public key: ${addressObjectMatches}`)
// Step 8: Summary - all encoding methods produce 32 bytes printStep(8, 'Summary - All Encoding Methods')
printInfo('ABIAddressType accepts:') printInfo(' 1. Address string (base32 format, 58 chars) -> extracts public key') printInfo(' 2. Uint8Array (32 bytes) -> uses directly') printInfo(' 3. Address object -> extracts publicKey property')
printInfo('\nAll methods produce exactly 32 bytes (no length prefix):') printInfo(` From string: ${addressType.encode(sampleAddressString).length} bytes`) printInfo(` From Uint8Array: ${addressType.encode(rawPublicKey).length} bytes`) printInfo(` From Address: ${addressType.encode(addressObject).length} bytes`)
printInfo('\nDecode always returns base32 address string (58 chars)')
printSuccess('ABI Address Type example completed successfully!')}
main()