Matrix logo

ABI Encoder

The ABI encoder bridges JSON-decoded values to the exact Go types required by go-ethereum's ABI packer for method calls and constructor arguments.

Source file: internal/abienc/abienc.go

The ABI encoder bridges JSON-decoded values to the exact Go types required by go-ethereum's ABI packer. JSON decoding produces float64/string/bool/[]interface{}/map[string]interface{}; the ABI packer needs *big.Int for uint256, common.Address for addresses, [N]byte for fixed bytes, etc. This package coerces each value into the precise Go type the ABI expects, driven by the contract ABI itself.


Design decisions

JSON-to-Go type coercion, not schema validation

The encoder does not validate that the JSON matches the ABI schema. It coerces each value into the Go type the ABI expects. If coercion fails, it returns a detailed error (arg %d (%s): %w). This is sufficient for agent use because agents typically construct well-formed JSON args.

Integer handling

uint256 and other large integers are represented as strings in JSON (decimal or 0x hex) to avoid JavaScript's 2^53 precision limit. The encoder parses these strings into *big.Int:

func toBigInt(v interface{}) (*big.Int, error)

Supported input types:

  • *big.Int - passthrough
  • json.Number - decimal string
  • string - decimal or 0x hex
  • float64 - converted via big.NewFloat (rejects non-integral)

For ABI types smaller than 256 bits, the encoder returns the exact Go type (int8/16/32/64, uint8/16/32/64) to satisfy go-ethereum's packer. The size-to-type mapping:

ABI sizeSignedUnsigned
8int8uint8
16int16uint16
32int32uint32
64int64uint64
128/256*big.Int*big.Int

Tuple support

Tuples accept either:

  • An ordered JSON array (positional)
  • A JSON object keyed by Solidity field names (named, using TupleRawNames)
// Array form:
["0xRecipient", "1000000000000000000"]

// Object form:
{"to": "0xRecipient", "amount": "1000000000000000000"}

Array/slice support

Dynamic arrays (uint256[]) and fixed arrays (uint256[3]) are both supported. The encoder builds the correct Go slice or array type via reflection. Fixed arrays enforce element count.

Bytes support

  • bytes (dynamic): hex string to []byte
  • bytesN (fixed): hex string to [N]byte via reflection, with length validation

API

// Pack a method call (4-byte selector + arguments)
func Pack(abiJSON []byte, method string, args any) ([]byte, error)

// Pack constructor arguments (no selector, for appending to creation bytecode)
func PackConstructorArgs(abiJSON []byte, args any) ([]byte, error)

Both functions accept args as nil, []interface{}, json.RawMessage, or any value that marshals to a JSON array.


Coercion matrix

ABI typeJSON inputGo output
int8-int256number/stringint8/16/32/64 or *big.Int
uint8-uint256number/stringuint8/16/32/64 or *big.Int
boolbooleanbool
stringstringstring
addresshex stringcommon.Address
byteshex string[]byte
bytesNhex string[N]byte
T[]array[]T
T[N]array[N]T
tuplearray or objectstruct

Modifying the ABI encoder

What to changeWhere
Add new ABI typeinternal/abienc/abienc.go - coerce switch
Change integer parsinginternal/abienc/abienc.go - toBigInt
Add tuple field aliasinternal/abienc/abienc.go - coerceTuple
Add struct tag supportinternal/abienc/abienc.go - use reflect tags