Skip to content

ABI Encoding

← Back to Examples Overview

ABI type parsing, encoding, and decoding following the ARC-4 specification.

ExampleDescription
ABI Type Parsing

This example demonstrates how to parse ABI type strings into type objects using ABIType.from(). It shows parsing of:

  • Primitive types: uint8, uint64, uint256, bool, byte, address, string
  • Array types: uint64[], byte[32], address[5]
  • Tuple types: (uint64,address), (bool,string,uint256)

And demonstrates type properties and instanceof checks for type category detection.

ABI Primitive Types

This example demonstrates how to encode and decode primitive ABI types:

  • ABIUintType: Unsigned integers of various bit sizes (8, 16, 32, 64, 128, 256, 512)
  • ABIBoolType: Boolean values encoded as a single byte
  • ABIByteType: Single byte values

Shows encode() and decode() methods, hex format display, and round-trip verification.

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.

ABI String Type

This example demonstrates how to encode and decode dynamic strings using ABIStringType:

  • ABIStringType encodes strings with a 2-byte length prefix followed by UTF-8 content
  • Shows encoding of empty strings, ASCII text, and Unicode characters
  • Demonstrates that strings are dynamic types (variable length)
  • Displays byte breakdown: length prefix vs content bytes
ABI Static Array Type

This example demonstrates how to encode and decode fixed-length arrays using ABIArrayStaticType:

  • byte[32]: Fixed 32 bytes, common for hashes and cryptographic data
  • uint64[3]: Fixed array of 3 unsigned 64-bit integers
  • address[2]: Fixed array of 2 Algorand addresses

Key characteristics of static arrays:

  • Fixed length known at compile time
  • No length prefix in encoding (unlike dynamic arrays)
  • Elements are encoded consecutively
  • Encoded length = elementSize * arrayLength
ABI Dynamic Array Type

This example demonstrates how to encode and decode variable-length arrays using ABIArrayDynamicType:

  • uint64[]: Dynamic array of unsigned 64-bit integers
  • string[]: Dynamic array of strings (nested dynamic types)
  • address[]: Dynamic array of Algorand addresses

Key characteristics of dynamic arrays:

  • Variable length determined at runtime
  • 2-byte (uint16) length prefix indicating number of elements
  • For static element types: elements encoded consecutively after length
  • For dynamic element types: head/tail encoding pattern is used

Head/Tail encoding (for arrays containing dynamic elements):

  • Length prefix: 2 bytes indicating number of elements
  • Head section: Contains offsets (2 bytes each) pointing to where each element starts in tail
  • Tail section: Contains the actual encoded elements
ABI Tuple Type

This example demonstrates how to encode and decode tuples using ABITupleType:

  • Tuples with mixed static types: (uint64,bool,address)
  • Tuples with dynamic types: (uint64,string,bool)
  • Nested tuples: ((uint64,bool),string)

Key characteristics of tuple encoding:

  • Static-only tuples: all elements encoded consecutively, fixed size
  • Tuples with dynamic elements: head/tail encoding pattern
  • Head: static values inline + offsets for dynamic values
  • Tail: actual data for dynamic elements
  • Nested tuples: inner tuples are encoded first, then treated as their component

ARC-4 specification: Tuples are sequences of types enclosed in parentheses.

ABI Struct Type

This example demonstrates how to encode and decode named structs using ABIStructType:

  • Creating ABIStructType with named fields
  • Encoding struct values as objects with named keys
  • Comparing struct encoding to equivalent tuple encoding
  • Accessing struct field names and types
  • Decoding back to struct values with named fields

Key characteristics of struct encoding:

  • Structs are named tuples - the encoding is identical to the equivalent tuple
  • Field names provide semantic meaning but don’t affect the binary encoding
  • Decoded values are objects with named properties (not arrays like tuples)

ARC-4 specification: Structs are tuples with named fields for improved readability.

ABI Struct and Tuple Conversion

This example demonstrates how to convert between struct values (named) and tuple values (positional):

  • getTupleValueFromStructValue(): Convert struct object to tuple array
  • getStructValueFromTupleValue(): Convert tuple array back to struct object
  • Simple struct { name: ‘Alice’, age: 30n } <-> tuple [‘Alice’, 30n]
  • Nested structs with complex types
  • Verify that struct and tuple encodings produce identical bytes

Key concept: Structs and tuples have identical binary encoding in ARC-4. The conversion functions allow you to work with the same data in either format:

  • Struct format: object with named properties (more readable)
  • Tuple format: array with positional elements (matches ABI encoding)
ABI Bool Array Packing

This example demonstrates how bool arrays are packed efficiently in ARC-4:

  • 8 booleans fit in 1 byte (1 bit per boolean)
  • bool[8] encodes to exactly 1 byte
  • bool[16] encodes to 2 bytes
  • Partial byte arrays (e.g., bool[5]) still use full bytes

Key characteristics of bool array packing:

  • Each bool is stored as a single bit, not a full byte
  • Bools are packed left-to-right starting from the MSB (most significant bit)
  • Array length is rounded up to the next full byte
  • This is much more space-efficient than storing each bool as uint8
ABI Method

This example demonstrates how to work with ABI methods:

  • Parsing method signatures with ABIMethod.fromSignature()
  • Accessing method name, args, and return type
  • Generating 4-byte method selectors with getSelector()
  • Understanding the relationship: selector = first 4 bytes of SHA-512/256(signature)

ABI method signatures follow the pattern: name(arg1Type,arg2Type,…)returnType Examples: ‘transfer(address,uint64)uint64’, ‘hello(string)string’

AVM Type Encoding

This example demonstrates how to work with AVM-specific types:

  • AVMBytes: Raw byte arrays (no length prefix, unlike ABI string/bytes)
  • AVMString: UTF-8 strings (no length prefix, unlike ABI string)
  • AVMUint64: 64-bit unsigned integers (8 bytes, big-endian)

AVM types represent how data is stored natively on the AVM stack, while ABI types follow the ARC-4 encoding specification with length prefixes.

Key functions:

  • getABIEncodedValue(avmType, value): Encode a value (works with both AVM and ABI types)
  • decodeAVMValue(avmType, bytes): Decode AVM bytes back to a value
  • isAVMType(type): Check if a type string is an AVM type
Type Guards

This example demonstrates how to use type guard functions to check argument and type categories in the ABI system:

  • argTypeIsTransaction(): Check if type is a transaction type (txn, pay, keyreg, acfg, axfer, afrz, appl)
  • argTypeIsReference(): Check if type is a reference type (account, asset, application)
  • argTypeIsAbiType(): Check if type is a standard ABI type (not transaction or reference)
  • isAVMType(): Check if type is an AVM-specific type (AVMBytes, AVMString, AVMUint64)

These guards are essential for:

  • Method argument handling and routing
  • TypeScript type narrowing for safer code
  • Determining how to encode/decode values based on type category
ABI Complex Nested Types

This example demonstrates how to work with deeply nested ABI types combining arrays, tuples, and structs:

  • Array of tuples: (uint64,string)[]
  • Tuple containing arrays: (uint64[],string[])
  • Nested structs with arrays
  • Deeply nested type: ((uint64,bool)[],string,(address,uint256))[]

Key concepts:

  • Dynamic types (strings, dynamic arrays) always use head/tail encoding
  • Offsets in head section point to data positions in tail section
  • Nesting depth affects encoding complexity but follows consistent rules
  • Round-trip encoding/decoding preserves all nested values
ARC-56 Storage Helpers

This example demonstrates how to use ARC-56 storage helpers to inspect contract state key definitions and maps from an ARC-56 contract specification:

Storage Key Functions:

  • getGlobalABIStorageKeys(): Get all global state key definitions
  • getLocalABIStorageKeys(): Get all local state key definitions
  • getBoxABIStorageKeys(): Get all box key definitions

Storage Map Functions:

  • getBoxABIStorageMaps(): Get box map definitions

ABIStorageKey properties:

  • key: Base64-encoded key bytes
  • keyType: The type of the key (ABIType or AVMType)
  • valueType: The type of the value (ABIType or AVMType)
  • desc?: Optional description

ABIStorageMap properties:

  • keyType: The type of keys in the map
  • valueType: The type of values in the map
  • desc?: Optional description
  • prefix?: Base64-encoded prefix for map keys

The example also deploys a contract to LocalNet and reads actual state values.

Run any example from the repository’s examples directory:

Terminal window
cd examples
npm run example abi/01-*.ts