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_string(). 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 isinstance checks for type category detection.

ABI Primitive Types

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

  • UintType: Unsigned integers of various bit sizes (8, 16, 32, 64, 128, 256, 512)
  • BoolType: Boolean values encoded as a single byte
  • ByteType: 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 AddressType:

  • Encoding address strings (base32 format) to 32 bytes
  • Encoding raw 32-byte public key (bytes)
  • 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 StringType:

  • StringType 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 StaticArrayType:

  • 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 DynamicArrayType:

  • 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 TupleType:

  • 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 StructType:

  • Creating StructType 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):

  • get_tuple_from_struct(): Convert struct dict to tuple
  • get_struct_from_tuple(): Convert tuple back to struct dict
  • Simple struct { name: ‘Alice’, age: 30n } <-> tuple (‘Alice’, 30)
  • 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: dict with named properties (more readable)
  • Tuple format: tuple 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 Method.from_signature()
  • Accessing method name, args, and return type
  • Generating 4-byte method selectors with get_selector()
  • 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.

The Python SDK provides the AVMType enum in algokit_abi.arc56 with values: AVMType.BYTES, AVMType.STRING, AVMType.UINT64

Type Guards

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

  • TransactionType: Check if type is a transaction type (txn, pay, keyreg, acfg, axfer, afrz, appl)
  • ReferenceType: Check if type is a reference type (account, asset, application)
  • ABIType: Standard ABI types (not transaction or reference)
  • AVMType: AVM-specific types (AVMBytes, AVMString, AVMUint64)

In Python, use isinstance() checks with TransactionType and ReferenceType enums, and the abi.ABIType base class to determine type categories.

These checks are essential for:

  • Method argument handling and routing
  • 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 Properties (StorageKey):

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

Storage Map Properties (StorageMap):

  • key_type: The type of keys in the map
  • value_type: The type of values in the map
  • desc: Optional description
  • prefix: Base64-encoded prefix for map keys

In the Python SDK, access storage definitions via:

  • contract.state.keys.global_state - Global state keys
  • contract.state.keys.local_state - Local state keys
  • contract.state.keys.box - Box storage keys
  • contract.state.maps.global_state - Global state maps
  • contract.state.maps.local_state - Local state maps
  • contract.state.maps.box - Box storage maps

Run any example from the repository’s examples directory:

Terminal window
cd examples
uv run python abi/01_type_parsing.py