Skip to main content
Use this page when you need the model behind ABI YAML before you start debugging layout behavior or designing advanced dynamic types.
This page is intentionally shorter than the internal ABI design material. Treat the ABI tooling itself, especially analyze, reflect, and codegen, as the current source of truth when command behavior and prose ever diverge.

Design Goals

Deterministic

ABI layouts are byte-for-byte reproducible so every backend sees the same structure.

Zero-Copy Friendly

The format is designed so generated code can access buffers directly instead of copying data out first.

Cross-Language

The same ABI definition can drive C, Rust, TypeScript, and reflection tooling.

Core Rules

RuleWhat to keep in mind
EndiannessMulti-byte values are little-endian.
Primitive typesThe core type system includes signed and unsigned integers, floating-point types, and char.
Struct layoutPacked structs have no padding. Aligned structs insert padding based on natural alignment.
ArraysArrays can be fixed-size or runtime-sized through field references.
Flexible Array MembersOnce the first runtime-sized field appears, offsets for later fields become runtime-dependent.
Enums and unionsVariant layout and discriminator rules must still yield deterministic validation behavior.
Dynamic parametersRuntime-sized fields, tags, and payload sizes are tracked explicitly so validators, reflection, and codegen can agree on the same layout math.

What ABI YAML Represents

At a high level, an ABI file contains:
  • package metadata such as package name and version
  • optional imports
  • named type definitions
The type system supports:
  • primitive fields
  • structs
  • unions
  • enums
  • fixed-size arrays
  • variable-size arrays whose size is driven by earlier fields
  • references to imported or previously defined types

Imports

The ABI toolchain supports multiple import sources:
  • local path imports
  • git imports
  • HTTP imports
  • on-chain imports
That flexibility is useful, but it changes the safe publishing workflow:
  • local imports are fine while you are writing and testing
  • on-chain publishing requires those local imports to be inlined or otherwise normalized first
The important authoring rule is that remote files cannot depend on local filesystem paths. Use Authoring Guide for how to structure imports and Publishing and Iteration for the publish-safe workflow.

Dynamic Layouts

The hardest ABI cases are the ones with runtime-sized fields. Common examples:
  • a name_len field followed by a byte array of that size
  • nested field references such as box.first
  • arrays whose element counts depend on earlier fields
  • expressions over nested array elements such as state proof bitsets
Those layouts are valid, but they are also where mistakes tend to surface first. Prefer to validate them with:

Practical Interpretation

  • Put the field that drives a variable-length array before the variable field itself.
  • Expect fully flattened or publish-ready artifacts to differ from your authoring-time source if you use local imports.
  • Treat analyze --print-ir as the fastest way to inspect what the toolchain thinks the layout really is.

Use This Spec Efficiently