# `ABI.FunctionSelector`
[🔗](https://github.com/ZenHive/hieroglyph/blob/main/lib/abi/function_selector.ex#L1)

Module to help parse the ABI function signatures, e.g.
`my_function(uint64, string[])`.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `encode` | 3 | Render a FunctionSelector struct as its canonical Solidity signature string, optionally annotating indexed event params and parameter names. | `function_selector: value`, `indexed: value`, `names: value` |
| `decode_type` | 1 | Parse a single Solidity type expression into the internal type representation. Useful for one-off type parsing without function-name framing. | `single_type: value` |
| `parse_specification_item` | 1 | Parse a single ABI specification item (function, event, fallback, receive, error) from a decoded JSON ABI map into a FunctionSelector struct. | `item: value` |
| `decode_raw` | 1 | Parse a comma-separated list of Solidity type names into a list of internal type representations, without function-name framing. | `type_string: value` |
| `decode` | 1 | Parse a Solidity function or event signature string into a FunctionSelector struct exposing function name, parameter types, and (when present) named parameters. | `signature: value` |

# `argument_type`

```elixir
@type argument_type() :: %{
  :type =&gt; type(),
  optional(:name) =&gt; String.t(),
  optional(:indexed) =&gt; boolean()
}
```

# `function_type`

```elixir
@type function_type() ::
  :function | :constructor | :fallback | :receive | :error | :event
```

# `state_mutability`

```elixir
@type state_mutability() :: :nonpayable | :pure | :view | :payable
```

# `t`

```elixir
@type t() :: %ABI.FunctionSelector{
  function: String.t() | nil,
  function_type: function_type() | nil,
  returns: type() | [argument_type()] | nil,
  state_mutability: state_mutability() | nil,
  types: [argument_type()]
}
```

# `type`

```elixir
@type type() ::
  {:uint, integer()}
  | :bool
  | :bytes
  | {:bytes, pos_integer()}
  | :string
  | :address
  | :function
  | {:int, integer()}
  | {:array, type()}
  | {:array, type(), non_neg_integer()}
  | {:tuple, [argument_type()]}
```

A Solidity ABI type.

Note that `address payable` is **not** a distinct variant. Solidity ABI
JSON only emits `"address"` for both `address` and `address payable`,
and the on-the-wire encoding is identical (20-byte left-padded). Payability
is a property of function state mutability (`:payable` in
`t:state_mutability/0`), not the address type itself, so both forms
collapse to `:address` here.

# `decode`

```elixir
@spec decode(String.t()) :: t()
```

Decodes a function selector to a struct.

## Examples

    iex> ABI.FunctionSelector.decode("bark(uint256,bool)")
    %ABI.FunctionSelector{
      function: "bark",
      types: [
        %{type: {:uint, 256}},
        %{type: :bool}
      ]
    }

    iex> ABI.FunctionSelector.decode("bark(uint256 name, bool loud)")
    %ABI.FunctionSelector{
      function: "bark",
      types: [
        %{type: {:uint, 256}, name: "name"},
        %{type: :bool, name: "loud"}
      ]
    }

    iex> ABI.FunctionSelector.decode("bark(uint256 name,bool indexed loud)")
    %ABI.FunctionSelector{
      function: "bark",
      types: [
        %{type: {:uint, 256}, name: "name"},
        %{type: :bool, name: "loud", indexed: true}
      ]
    }

    iex> ABI.FunctionSelector.decode("(uint256,bool)")
    %ABI.FunctionSelector{
      function: nil,
      types: [
        %{type: {:uint, 256}},
        %{type: :bool}
      ]
    }

    iex> ABI.FunctionSelector.decode("growl(uint,address,string[])")
    %ABI.FunctionSelector{
      function: "growl",
      types: [
        %{type: {:uint, 256}},
        %{type: :address},
        %{type: {:array, :string}}
      ]
    }

    iex> ABI.FunctionSelector.decode("rollover()")
    %ABI.FunctionSelector{
      function: "rollover",
      types: []
    }

    iex> ABI.FunctionSelector.decode("do_playDead3()")
    %ABI.FunctionSelector{
      function: "do_playDead3",
      types: []
    }

    iex> ABI.FunctionSelector.decode("pet(address[])")
    %ABI.FunctionSelector{
      function: "pet",
      types: [
        %{type: {:array, :address}}
      ]
    }

    iex> ABI.FunctionSelector.decode("paw(string[2])")
    %ABI.FunctionSelector{
      function: "paw",
      types: [
        %{type: {:array, :string, 2}}
      ]
    }

    iex> ABI.FunctionSelector.decode("scram(uint256[])")
    %ABI.FunctionSelector{
      function: "scram",
      types: [
        %{type: {:array, {:uint, 256}}}
      ]
    }

    iex> ABI.FunctionSelector.decode("shake((string))")
    %ABI.FunctionSelector{
      function: "shake",
      types: [
        %{type: {:tuple, [%{type: :string}]}}
      ]
    }

# `decode_raw`

```elixir
@spec decode_raw(String.t()) :: [type()]
```

Decodes the given type-string as a simple array of types.

## Examples

    iex> ABI.FunctionSelector.decode_raw("string,uint256")
    [:string, {:uint, 256}]

    iex> ABI.FunctionSelector.decode_raw("")
    []

# `decode_type`

```elixir
@spec decode_type(String.t()) :: type()
```

Decodes the given type-string as a single type.

## Examples

    iex> ABI.FunctionSelector.decode_type("uint256")
    {:uint, 256}

    iex> ABI.FunctionSelector.decode_type("(bool,address)")
    {:tuple, [%{type: :bool}, %{type: :address}]}

    iex> ABI.FunctionSelector.decode_type("address[][3]")
    {:array, {:array, :address}, 3}

# `encode`

```elixir
@spec encode(t(), boolean(), boolean()) :: String.t()
```

Encodes a function call signature. If `indexed=true`, returns
the `"indexed"` keyword after indexed parameters.

## Example

    iex> ABI.FunctionSelector.encode(%ABI.FunctionSelector{
    ...>   function: "bark",
    ...>   types: [
    ...>     %{type: {:uint, 256}},
    ...>     %{type: :bool, indexed: true},
    ...>     %{type: {:array, :string}},
    ...>     %{type: {:array, :string, 3}},
    ...>     %{type: {:tuple, [%{type: {:uint, 256}}, %{type: :bool}]}}
    ...>   ]
    ...> })
    "bark(uint256,bool,string[],string[3],(uint256,bool))"

    iex> ABI.FunctionSelector.encode(%ABI.FunctionSelector{
    ...>   function: "bark",
    ...>   types: [
    ...>     %{type: {:uint, 256}},
    ...>     %{type: :bool, indexed: true},
    ...>     %{type: {:array, :string}},
    ...>     %{type: {:array, :string, 3}},
    ...>     %{type: {:tuple, [%{type: {:uint, 256}}, %{type: :bool}]}}
    ...>   ]
    ...> }, true)
    "bark(uint256,bool indexed,string[],string[3],(uint256,bool))"

    iex> ABI.FunctionSelector.encode(%ABI.FunctionSelector{
    ...>   function: "bark",
    ...>   types: [
    ...>     %{type: {:uint, 256}},
    ...>     %{type: :bool, indexed: true},
    ...>     %{type: {:array, :string}},
    ...>     %{type: {:array, :string, 3}},
    ...>     %{type: {:tuple, [%{type: {:uint, 256}}, %{type: :bool}]}}
    ...>   ]
    ...> }, true, true)
    "bark(uint256 var0,bool indexed var1,string[] var2,string[3] var3,(uint256,bool) var4)"

    iex> ABI.FunctionSelector.encode(%ABI.FunctionSelector{
    ...>   function: "bark",
    ...>   types: [
    ...>     %{type: {:uint, 256}},
    ...>     %{type: :bool, indexed: true},
    ...>     %{type: {:array, :string}},
    ...>     %{type: {:array, :string, 3}},
    ...>     %{type: {:tuple, [%{type: {:uint, 256}}, %{type: :bool}]}}
    ...>   ]
    ...> }, false, true)
    "bark(uint256 var0,bool var1,string[] var2,string[3] var3,(uint256,bool) var4)"

    iex> ABI.FunctionSelector.encode(%ABI.FunctionSelector{
    ...>   function: "bark",
    ...>   types: [
    ...>     %{type: {:uint, 256}, name: "a"},
    ...>     %{type: :bool, indexed: true, name: "b"},
    ...>     %{type: {:array, :string}, name: "c"},
    ...>     %{type: {:array, :string, 3}, name: "d"},
    ...>     %{type: {:tuple, [%{type: {:uint, 256}}, %{type: :bool}]}, name: "e"}
    ...>   ]
    ...> }, false, true)
    "bark(uint256 a,bool b,string[] c,string[3] d,(uint256,bool) e)"

# `parse_specification_item`

```elixir
@spec parse_specification_item(map()) :: t()
```

Parse a function selector, e.g. from an abi.json file.

## Examples

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "function", "name" => "fun", "inputs" => [%{"name" => "a", "type" => "uint96", "internalType" => "uint96"}]})
    %ABI.FunctionSelector{
      function: "fun",
      function_type: :function,
      types: [%{type: {:uint, 96}, name: "a"}],
      returns: nil
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "function", "name" => "fun", "inputs" => [%{"name" => "s", "type" => "tuple", "internalType" => "tuple", "components" => [%{"name" => "a", "type" => "uint256", "internalType" => "uint256"},%{"name" => "b", "type" => "address", "internalType" => "address"},%{"name" => "c", "type" => "bytes", "internalType" => "bytes"}]},%{"name" => "d", "type" => "uint256", "internalType" => "uint256"}],"outputs" => [%{"name" => "", "type" => "bytes", "internalType" => "bytes"}],"stateMutability" => "view"})
    %ABI.FunctionSelector{
      function: "fun",
      function_type: :function,
      state_mutability: :view,
      types: [
        %{
          type:
            {:tuple, [
              %{type: {:uint, 256}, name: "a"},
              %{type: :address, name: "b"},
              %{type: :bytes, name: "c"}
            ]},
            name: "s"
        }, %{
          type: {:uint, 256},
          name: "d"
        }
      ],
      returns: [%{name: "", type: :bytes}],
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "function", "name" => "fun", "inputs" => [%{"name" => "s", "type" => "tuple", "internalType" => "struct Contract.Struct", "components" => [%{"name" => "a", "type" => "uint256", "internalType" => "uint256"},%{"name" => "b", "type" => "address", "internalType" => "address"},%{"name" => "c", "type" => "bytes", "internalType" => "bytes"}]},%{"name" => "d", "type" => "uint256", "internalType" => "uint256"}],"outputs" => [%{"name" => "", "type" => "bytes", "internalType" => "bytes"}],"stateMutability" => "pure"})
    %ABI.FunctionSelector{
      function: "fun",
      function_type: :function,
      state_mutability: :pure,
      types: [
        %{
          type:
            {:tuple, [
              %{type: {:uint, 256}, name: "a"},
              %{type: :address, name: "b"},
              %{type: :bytes, name: "c"}
            ]},
            name: "s"
        }, %{
          type: {:uint, 256},
          name: "d"
        }
      ],
      returns: [%{name: "", type: :bytes}],
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "function", "name" => "fun", "inputs" => [%{"name" => "s", "type" => "tuple", "internalType" => "struct Contract.Struct", "components" => [%{"name" => "a", "type" => "uint256", "internalType" => "uint256"},%{"type" => "address", "internalType" => "address"},%{"name" => "c", "type" => "bytes", "internalType" => "bytes"}]},%{"name" => "d", "type" => "uint256", "internalType" => "uint256"}],"outputs" => [%{"name" => "", "type" => "bytes", "internalType" => "bytes"}],"stateMutability" => "payable"})
    %ABI.FunctionSelector{
      function: "fun",
      function_type: :function,
      state_mutability: :payable,
      types: [
        %{
          type:
            {:tuple, [
              %{type: {:uint, 256}, name: "a"},
              %{type: :address},
              %{type: :bytes, name: "c"}
            ]},
            name: "s"
        }, %{
          type: {:uint, 256},
          name: "d"
        }
      ],
      returns: [%{name: "", type: :bytes}],
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "fallback"})
    %ABI.FunctionSelector{
      function: nil,
      function_type: :fallback,
      types: [],
      returns: nil
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"type" => "receive"})
    %ABI.FunctionSelector{
      function: nil,
      function_type: :receive,
      types: [],
      returns: nil
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"inputs" => [%{"internalType" => "address[]", "name" => "xs", "type" => "address[]"}, %{"internalType" => "bytes[]", "name" => "ys", "type" => "bytes[]"}, %{"components" => [%{"internalType" => "enum Z", "name" => "za", "type" => "uint8"}, %{"internalType" => "enum Z", "name" => "zb", "type" => "uint8"}], "internalType" => "struct Z.Z[]", "name" => "zs", "type" => "tuple[]"}, %{"internalType" => "bytes[]", "name" => "zz", "type" => "bytes[]"}], "name" => "go", "outputs" => [%{"internalType" => "bytes[]", "name" => "", "type" => "bytes[]"}], "stateMutability" => "nonpayable", "type" => "function"})
    %ABI.FunctionSelector{
      function: "go",
      function_type: :function,
      state_mutability: :nonpayable,
      types: [
        %{name: "xs", type: {:array, :address}},
        %{name: "ys", type: {:array, :bytes}},
        %{
          name: "zs",
          type:
            {:array,
             {:tuple,
              [%{name: "za", type: {:uint, 8}}, %{name: "zb", type: {:uint, 8}}]}}
        },
        %{name: "zz", type: {:array, :bytes}}
      ],
      returns: [%{name: "", type: {:array, :bytes}}]
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"anonymous" => false, "inputs" => [%{"indexed" => true, "internalType" => "address", "name" => "z0", "type" => "address"}, %{"indexed" => true, "internalType" => "address", "name" => "z1", "type" => "address"}, %{"indexed" => false, "internalType" => "address", "name" => "z2", "type" => "address"}, %{"indexed" => false, "internalType" => "bytes32", "name" => "z3", "type" => "bytes32"}], "name" => "z4", "type" => "event"})
    %ABI.FunctionSelector{
      function: "z4",
      function_type: :event,
      state_mutability: nil,
      types: [
        %{name: "z0", type: :address, indexed: true},
        %{name: "z1", type: :address, indexed: true},
        %{name: "z2", type: :address, indexed: false},
        %{name: "z3", type: {:bytes, 32}, indexed: false}
      ],
      returns: nil
    }

    iex> ABI.FunctionSelector.parse_specification_item(%{"inputs" => [], "name" => "Abc", "type" => "error"})
    %ABI.FunctionSelector{function: "Abc", function_type: :error, state_mutability: nil, types: [], returns: nil}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
