Onchain.ABI (onchain v0.5.4)

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.

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

Functions

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

API Functions

FunctionArityDescriptionParam Kinds
decode_error!2Decode custom-error revert data. Raises on error.hex_revert_data: value, error_definitions: value
decode_error2Decode Solidity 0.8.4+ custom-error revert data against a list of candidate error signatures.hex_revert_data: value, error_definitions: 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!2Decode arbitrary ABI-encoded hex data. Alias of decode_response!/2.type_signature: value, hex_data: value
decode_types2Decode arbitrary ABI-encoded hex data. Alias of decode_response/2.type_signature: value, hex_data: value
decode_response!2Decode hex-encoded ABI response data to Elixir values. Raises on error.type_signature: value, hex_data: value
decode_response2Decode hex-encoded ABI response data to Elixir values.type_signature: value, hex_data: 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/2.

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

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. (default: [], value)

Returns

List of args (or map when decode_structs: true). Error reasons: :calldata_too_short, :selector_mismatch, :no_function_name, {:invalid_hex, _}, 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.",
      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, _}`, 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) (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`)",
      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)

@spec decode_error(String.t(), [String.t() | ABI.FunctionSelector.t()]) ::
  {:ok, %{error: String.t() | nil, args: list()}}
  | {: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)

Returns

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

# descripex:contract
%{
  params: %{
    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, _}`, or upstream exception message string."
  }
}

decode_error!(hex_revert_data, error_definitions)

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

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)

Returns

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

# descripex:contract
%{
  params: %{
    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)

@spec decode_response(String.t(), String.t()) ::
  {:ok, list()} | {: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)

Returns

List of decoded values ({:ok, list} | {:error, {:decode_error, reason}})

# descripex:contract
%{
  params: %{
    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} | {:error, {:decode_error, reason}}",
    description: "List of decoded values"
  }
}

decode_response!(type_signature, hex_data)

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

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)

Returns

List of decoded values (list)

# descripex:contract
%{
  params: %{
    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: :list, description: "List of decoded values"}
}

decode_types(type_signature, hex_data)

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

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

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)

Returns

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

# descripex:contract
%{
  params: %{
    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} | {:error, {:decode_error, reason}}",
    description: "List of decoded values. Identical to decode_response/2 — use this name when the input isn't an RPC response (mempool calldata, custom ABI payloads)."
  }
}

decode_types!(type_signature, hex_data)

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

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

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)

Returns

List of decoded values (list)

# descripex:contract
%{
  params: %{
    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: :list, description: "List of decoded values"}
}

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"}
}