Onchain.ABI (onchain v0.14.0)

Copy Markdown View Source

ABI encoding/decoding for Ethereum contract calls.

Wraps the hieroglyph ABI library (transitively pulled in by cartouche) with 0x-prefixed hex string handling and consistent error tuples. Consumers work with hex strings from RPC; this module bridges the gap.

Type Signatures

decode_response/2 (and its alias decode_types/2) expects tuple type syntax for return values — the type list MUST be wrapped in parentheses, e.g. "(uint256)" or "(uint256,bool)". Bare comma-separated types ("uint256,bool") raise an unhelpful upstream error and are not accepted. This is the standard pattern for decoding eth_call responses — NOT function signatures with names.

Use decode_response/2 when the input is an eth_call reply; use decode_types/2 when the input is arbitrary ABI-encoded bytes (mempool calldata, custom payloads). They behave identically.

Decode functions accept an optional trailing keyword forwarded unchanged to hieroglyph (ABI.decode/3, ABI.decode_call/3, ABI.decode_error/3). strict: true rejects non-canonical payloads; decode_structs: true returns a named-field map. The default (no opts / strict: false) stays permissive.

Error Format

  • Encode errors: {:error, {:encode_error, reason}}
  • Decode errors: {:error, {:decode_error, reason}}

Where reason is either:

  • A string from the upstream exception message
  • A tuple like {:invalid_hex, hex_data} preserving the original hex error
  • {:strict_violation, detail} when strict: true rejected a non-canonical payload (non-zero high padding on bool/uint/int, trailing bytes after the declared payload, or a string/bytes length prefix that exceeds the available data). Bang variants raise.

Functions

FunctionPurpose
encode_call/2Function signature + params → hex calldata
encode_call!/2Same, raises on error
decode_response/3Type signature + hex data → decoded values (optional decode opts)
decode_response!/3Same, raises on error
decode_types/3Alias of decode_response/3 for non-RPC callers
decode_types!/3Alias of decode_response!/3, raises on error
decode_call/3Selector-prefixed calldata → decoded function args (forwards opts)
decode_call!/3Same, raises on error
decode_error/3Solidity 0.8.4+ custom-error revert data → %{error, args} (optional decode opts)
decode_error!/3Same, raises on error

API Functions

FunctionArityDescriptionParam Kinds
decode_error!3Decode custom-error revert data. Raises on error.hex_revert_data: value, error_definitions: value, opts: value
decode_error3Decode Solidity 0.8.4+ custom-error revert data against a list of candidate error signatures.hex_revert_data: value, error_definitions: value, opts: value
decode_call!3Decode selector-prefixed calldata. Raises on error.signature_or_selector: value, hex_calldata: value, opts: value
decode_call3Decode selector-prefixed calldata to function args.signature_or_selector: value, hex_calldata: value, opts: value
decode_types!3Decode arbitrary ABI-encoded hex data. Alias of decode_response!/3.type_signature: value, hex_data: value, opts: value
decode_types3Decode arbitrary ABI-encoded hex data. Alias of decode_response/3.type_signature: value, hex_data: value, opts: value
decode_response!3Decode hex-encoded ABI response data to Elixir values. Raises on error.type_signature: value, hex_data: value, opts: value
decode_response3Decode hex-encoded ABI response data to Elixir values.type_signature: value, hex_data: value, opts: value
encode_call!2Encode a function call to 0x-prefixed hex calldata. Raises on error.signature: value, params: value
encode_call2Encode a function call to 0x-prefixed hex calldata.signature: value, params: value

Summary

Functions

Decode selector-prefixed calldata to function args.

Decode selector-prefixed calldata. Raises on error.

Decode Solidity 0.8.4+ custom-error revert data against a list of candidate error signatures.

Decode custom-error revert data. Raises on error.

Decode hex-encoded ABI response data to Elixir values.

Decode hex-encoded ABI response data to Elixir values. Raises on error.

Decode arbitrary ABI-encoded hex data. Alias of decode_response/3.

Decode arbitrary ABI-encoded hex data. Alias of decode_response!/3.

Encode a function call to 0x-prefixed hex calldata.

Encode a function call to 0x-prefixed hex calldata. Raises on error.

Functions

decode_call(signature_or_selector, hex_calldata, opts \\ [])

@spec decode_call(String.t() | ABI.FunctionSelector.t(), String.t(), keyword()) ::
  {:ok, list() | map()} | {:error, {:decode_error, term()}}

Decode selector-prefixed calldata to function args.

Parameters

  • signature_or_selector - Function signature like "transfer(address,uint256)" OR a hieroglyph FunctionSelector struct. The 4-byte selector of the signature must match the first 4 bytes of calldata. (value)
  • hex_calldata - 0x-prefixed hex string of selector-prefixed ABI-encoded calldata (value)
  • opts - Forwarded to hieroglyph's ABI.decode_call/3. Pass decode_structs: true for a named-field map instead of a positional list. Pass strict: true to reject non-canonical payloads ({:error, {:decode_error, {:strict_violation, detail}}}). (default: [], value)

Returns

List of args (or map when decode_structs: true). Error reasons: :calldata_too_short, :selector_mismatch, :no_function_name, {:invalid_hex, _}, {:strict_violation, detail}, or upstream exception message string. ({:ok, list | map} | {:error, {:decode_error, reason}})

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode_call/3`. Pass `decode_structs: true` for a named-field map instead of a positional list. Pass `strict: true` to reject non-canonical payloads (`{:error, {:decode_error, {:strict_violation, detail}}}`).",
      kind: :value
    },
    signature_or_selector: %{
      description: "Function signature like \"transfer(address,uint256)\" OR a hieroglyph FunctionSelector struct. The 4-byte selector of the signature must match the first 4 bytes of calldata.",
      kind: :value
    },
    hex_calldata: %{
      description: "0x-prefixed hex string of selector-prefixed ABI-encoded calldata",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, list | map} | {:error, {:decode_error, reason}}",
    description: "List of args (or map when `decode_structs: true`). Error reasons: `:calldata_too_short`, `:selector_mismatch`, `:no_function_name`, `{:invalid_hex, _}`, `{:strict_violation, detail}`, or upstream exception message string."
  }
}

decode_call!(signature_or_selector, hex_calldata, opts \\ [])

@spec decode_call!(String.t() | ABI.FunctionSelector.t(), String.t(), keyword()) ::
  list() | map()

Decode selector-prefixed calldata. Raises on error.

Parameters

  • signature_or_selector - Function signature string or hieroglyph FunctionSelector struct (value)
  • hex_calldata - 0x-prefixed hex string of selector-prefixed calldata (value)
  • opts - Forwarded to hieroglyph's ABI.decode_call/3 (e.g. decode_structs: true, strict: true) (default: [], value)

Returns

List of decoded args (or map when decode_structs: true) (list | map)

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode_call/3` (e.g. `decode_structs: true`, `strict: true`)",
      kind: :value
    },
    signature_or_selector: %{
      description: "Function signature string or hieroglyph FunctionSelector struct",
      kind: :value
    },
    hex_calldata: %{
      description: "0x-prefixed hex string of selector-prefixed calldata",
      kind: :value
    }
  },
  returns: %{
    type: "list | map",
    description: "List of decoded args (or map when `decode_structs: true`)"
  }
}

decode_error(hex_revert_data, error_definitions, opts \\ [])

@spec decode_error(String.t(), [String.t() | ABI.FunctionSelector.t()], keyword()) ::
  {:ok, %{error: String.t() | nil, args: list() | map()}}
  | {:error, {:decode_error, term()}}

Decode Solidity 0.8.4+ custom-error revert data against a list of candidate error signatures.

Parameters

  • hex_revert_data - 0x-prefixed hex string of revert data (4-byte error selector + ABI-encoded args) (value)
  • error_definitions - List of candidate error signatures like ["InsufficientBalance(uint256,uint256)", "Unauthorized()"] (or hieroglyph FunctionSelector structs). The first one whose 4-byte selector matches the prefix of hex_revert_data decodes the args. (value)
  • opts - Forwarded to hieroglyph's ABI.decode_error/3. Pass strict: true to reject non-canonical payloads ({:error, {:decode_error, {:strict_violation, detail}}}). (default: [], value)

Returns

Map with the matched error name (or nil) and decoded args. Error reasons: :calldata_too_short, :no_match, {:invalid_hex, _}, {:strict_violation, detail}, or upstream exception message string. ({:ok, %{error: name, args: list}} | {:error, {:decode_error, reason}})

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode_error/3`. Pass `strict: true` to reject non-canonical payloads (`{:error, {:decode_error, {:strict_violation, detail}}}`).",
      kind: :value
    },
    error_definitions: %{
      description: "List of candidate error signatures like [\"InsufficientBalance(uint256,uint256)\", \"Unauthorized()\"] (or hieroglyph FunctionSelector structs). The first one whose 4-byte selector matches the prefix of `hex_revert_data` decodes the args.",
      kind: :value
    },
    hex_revert_data: %{
      description: "0x-prefixed hex string of revert data (4-byte error selector + ABI-encoded args)",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, %{error: name, args: list}} | {:error, {:decode_error, reason}}",
    description: "Map with the matched error name (or `nil`) and decoded args. Error reasons: `:calldata_too_short`, `:no_match`, `{:invalid_hex, _}`, `{:strict_violation, detail}`, or upstream exception message string."
  }
}

decode_error!(hex_revert_data, error_definitions, opts \\ [])

@spec decode_error!(String.t(), [String.t() | ABI.FunctionSelector.t()], keyword()) ::
  %{
    error: String.t() | nil,
    args: list() | map()
  }

Decode custom-error revert data. Raises on error.

Parameters

  • hex_revert_data - 0x-prefixed hex string of revert data (value)
  • error_definitions - List of candidate error signatures or FunctionSelector structs (value)
  • opts - Forwarded to hieroglyph's ABI.decode_error/3 (e.g. strict: true) (default: [], value)

Returns

Map with the matched error name and decoded args (%{error: name, args: list})

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode_error/3` (e.g. `strict: true`)",
      kind: :value
    },
    error_definitions: %{
      description: "List of candidate error signatures or FunctionSelector structs",
      kind: :value
    },
    hex_revert_data: %{
      description: "0x-prefixed hex string of revert data",
      kind: :value
    }
  },
  returns: %{
    type: "%{error: name, args: list}",
    description: "Map with the matched error name and decoded args"
  }
}

decode_response(type_signature, hex_data, opts \\ [])

@spec decode_response(String.t(), String.t(), keyword()) ::
  {:ok, list() | map()} | {:error, {:decode_error, term()}}

Decode hex-encoded ABI response data to Elixir values.

Parameters

  • type_signature - Tuple type signature wrapped in parentheses, e.g. "(uint256)" or "(uint256,bool)". Bare comma-separated types like "uint256,bool" are NOT accepted and raise an unhelpful upstream error. (value)
  • hex_data - 0x-prefixed hex string of ABI-encoded data (value)
  • opts - Forwarded to hieroglyph's ABI.decode/3. Pass strict: true to reject non-canonical padding, trailing bytes, and over-long dynamic length prefixes ({:error, {:decode_error, {:strict_violation, detail}}}). Pass decode_structs: true for a named-field map instead of a positional list. (default: [], value)

Returns

List of decoded values (or map when decode_structs: true). reason may be {:strict_violation, detail} when strict: true. ({:ok, list | map} | {:error, {:decode_error, reason}})

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode/3`. Pass `strict: true` to reject non-canonical padding, trailing bytes, and over-long dynamic length prefixes (`{:error, {:decode_error, {:strict_violation, detail}}}`). Pass `decode_structs: true` for a named-field map instead of a positional list.",
      kind: :value
    },
    type_signature: %{
      description: "Tuple type signature wrapped in parentheses, e.g. \"(uint256)\" or \"(uint256,bool)\". Bare comma-separated types like \"uint256,bool\" are NOT accepted and raise an unhelpful upstream error.",
      kind: :value
    },
    hex_data: %{
      description: "0x-prefixed hex string of ABI-encoded data",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, list | map} | {:error, {:decode_error, reason}}",
    description: "List of decoded values (or map when `decode_structs: true`). `reason` may be `{:strict_violation, detail}` when `strict: true`."
  }
}

decode_response!(type_signature, hex_data, opts \\ [])

@spec decode_response!(String.t(), String.t(), keyword()) :: list() | map()

Decode hex-encoded ABI response data to Elixir values. Raises on error.

Parameters

  • type_signature - Tuple type signature wrapped in parentheses, e.g. "(uint256)" or "(uint256,bool)". Bare comma-separated types are NOT accepted. (value)
  • hex_data - 0x-prefixed hex string of ABI-encoded data (value)
  • opts - Forwarded to hieroglyph's ABI.decode/3 (e.g. strict: true) (default: [], value)

Returns

List of decoded values (or map when decode_structs: true) (union)

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to hieroglyph's `ABI.decode/3` (e.g. `strict: true`)",
      kind: :value
    },
    type_signature: %{
      description: "Tuple type signature wrapped in parentheses, e.g. \"(uint256)\" or \"(uint256,bool)\". Bare comma-separated types are NOT accepted.",
      kind: :value
    },
    hex_data: %{
      description: "0x-prefixed hex string of ABI-encoded data",
      kind: :value
    }
  },
  returns: %{
    type: :union,
    description: "List of decoded values (or map when `decode_structs: true`)"
  }
}

decode_types(type_signature, hex_data, opts \\ [])

@spec decode_types(String.t(), String.t(), keyword()) ::
  {:ok, list() | map()} | {:error, {:decode_error, term()}}

Decode arbitrary ABI-encoded hex data. Alias of decode_response/3.

Parameters

  • type_signature - Tuple type signature wrapped in parentheses, e.g. "(uint256)" or "(uint256,bool)". Bare comma-separated types are NOT accepted. (value)
  • hex_data - 0x-prefixed hex string of ABI-encoded data (value)
  • opts - Forwarded to decode_response/3 (e.g. strict: true) (default: [], value)

Returns

List of decoded values. Identical to decode_response/3 — use this name when the input isn't an RPC response (mempool calldata, custom ABI payloads). ({:ok, list | map} | {:error, {:decode_error, reason}})

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to decode_response/3 (e.g. `strict: true`)",
      kind: :value
    },
    type_signature: %{
      description: "Tuple type signature wrapped in parentheses, e.g. \"(uint256)\" or \"(uint256,bool)\". Bare comma-separated types are NOT accepted.",
      kind: :value
    },
    hex_data: %{
      description: "0x-prefixed hex string of ABI-encoded data",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, list | map} | {:error, {:decode_error, reason}}",
    description: "List of decoded values. Identical to decode_response/3 — use this name when the input isn't an RPC response (mempool calldata, custom ABI payloads)."
  }
}

decode_types!(type_signature, hex_data, opts \\ [])

@spec decode_types!(String.t(), String.t(), keyword()) :: list() | map()

Decode arbitrary ABI-encoded hex data. Alias of decode_response!/3.

Parameters

  • type_signature - Tuple type signature wrapped in parentheses, e.g. "(uint256)" or "(uint256,bool)". Bare comma-separated types are NOT accepted. (value)
  • hex_data - 0x-prefixed hex string of ABI-encoded data (value)
  • opts - Forwarded to decode_response!/3 (e.g. strict: true) (default: [], value)

Returns

List of decoded values (or map when decode_structs: true) (union)

# descripex:contract
%{
  params: %{
    opts: %{
      default: [],
      description: "Forwarded to decode_response!/3 (e.g. `strict: true`)",
      kind: :value
    },
    type_signature: %{
      description: "Tuple type signature wrapped in parentheses, e.g. \"(uint256)\" or \"(uint256,bool)\". Bare comma-separated types are NOT accepted.",
      kind: :value
    },
    hex_data: %{
      description: "0x-prefixed hex string of ABI-encoded data",
      kind: :value
    }
  },
  returns: %{
    type: :union,
    description: "List of decoded values (or map when `decode_structs: true`)"
  }
}

encode_call(signature, params)

@spec encode_call(String.t(), list()) ::
  {:ok, String.t()} | {:error, {:encode_error, term()}}

Encode a function call to 0x-prefixed hex calldata.

Parameters

  • signature - Function signature, e.g. "balanceOf(address)" (value)
  • params - List of parameter values matching the signature (value)

Returns

0x-prefixed hex-encoded calldata ({:ok, hex_string} | {:error, {:encode_error, reason}})

# descripex:contract
%{
  params: %{
    signature: %{
      description: "Function signature, e.g. \"balanceOf(address)\"",
      kind: :value
    },
    params: %{
      description: "List of parameter values matching the signature",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, hex_string} | {:error, {:encode_error, reason}}",
    description: "0x-prefixed hex-encoded calldata",
    example: "0x70a08231..."
  }
}

encode_call!(signature, params)

@spec encode_call!(String.t(), list()) :: String.t()

Encode a function call to 0x-prefixed hex calldata. Raises on error.

Parameters

  • signature - Function signature, e.g. "balanceOf(address)" (value)
  • params - List of parameter values matching the signature (value)

Returns

0x-prefixed hex-encoded calldata (string)

# descripex:contract
%{
  params: %{
    signature: %{
      description: "Function signature, e.g. \"balanceOf(address)\"",
      kind: :value
    },
    params: %{
      description: "List of parameter values matching the signature",
      kind: :value
    }
  },
  returns: %{type: :string, description: "0x-prefixed hex-encoded calldata"}
}