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

`ABI.TypeEncoder` is responsible for encoding types to the format
expected by Solidity. We generally take a function selector and an
array of data and encode that array according to the specification.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `encode_packed` | 2 | Encodes values using Solidity's non-standard packed mode (abi.encodePacked) — types <32 bytes concatenated tight, dynamic types in-place without length prefix, array elements padded to 32 bytes. | `data: value`, `types: value` |
| `encode_raw` | 2 | Encode a list of values directly against an explicit type list, without prepending a method-id selector. Used for return values, event data, or pre-routed calldata payloads. | `data: value`, `types: value` |
| `encode` | 2 | Encode a list of values into ABI calldata using the given FunctionSelector, prefixing the 4-byte selector when the function name is set. | `data: value`, `function_selector: value` |

# `encode`

```elixir
@spec encode([any()], ABI.FunctionSelector.t()) :: binary()
```

Encodes the given data based on the function selector.

## Examples

    iex> [69, true]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: "baz",
    ...>        types: [
    ...>          %{type: {:uint, 32}},
    ...>          %{type: :bool}
    ...>        ],
    ...>        returns: :bool
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "cdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"

    iex> ["BAT"]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: "price",
    ...>        types: [
    ...>          %{type: :string}
    ...>        ],
    ...>        returns: {:uint, 256}
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "fe2c6198000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000"

    iex> [Base.decode16!("ffffffffffffffffffffffffffffffffffffffff", case: :lower)]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: "price",
    ...>        types: [
    ...>          %{type: :address}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "aea91078000000000000000000000000ffffffffffffffffffffffffffffffffffffffff"

    iex> [1]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: "price",
    ...>        types: [
    ...>          %{type: :address}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "aea910780000000000000000000000000000000000000000000000000000000000000001"

    iex> ["hello world"]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: :string},
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000"

    iex> [{{0x11, 0x22}, "hello world"}]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:tuple, [
    ...>            %{type: {:tuple, [%{type: {:uint, 256}},%{type: {:uint, 256}}]}},
    ...>            %{type: :string},
    ...>          ]}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000"

    iex> [{"awesome", true}]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:tuple, [%{type: :string}, %{type: :bool}]}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007617765736f6d6500000000000000000000000000000000000000000000000000"

    iex> [{17, true, <<32, 64>>}]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:tuple, [%{type: {:uint, 32}}, %{type: :bool}, %{type: {:bytes, 2}}]}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000012040000000000000000000000000000000000000000000000000000000000000"

    iex> [[17, 1]]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: "baz",
    ...>        types: [
    ...>          %{type: {:array, {:uint, 32}, 2}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "3d0ec53300000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"

    iex> [[17, 1], true]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:array, {:uint, 32}, 2}},
    ...>          %{type: :bool}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"

    iex> [[17, 1]]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:array, {:uint, 32}}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"

    iex> [
    ...>   <<1::160>>,
    ...>   <<2::160>>,
    ...>   <<3::256>>,
    ...>   {
    ...>     4,
    ...>     <<5::160>>,
    ...>     <<6>>,
    ...>     <<7::512>>,
    ...>     8
    ...>   },
    ...>   9,
    ...>   <<0xa::256>>,
    ...>   <<0xb::256>>
    ...> ]
    ...> |> ABI.TypeEncoder.encode(
    ...>   %ABI.FunctionSelector{
    ...>     function: "test",
    ...>     function_type: :function,
    ...>     state_mutability: :nonpayable,
    ...>     types: [
    ...>       %{name: "a", type: :address},
    ...>       %{name: "b", type: :address},
    ...>       %{name: "c", type: {:bytes, 32}},
    ...>       %{
    ...>         name: "d",
    ...>         type:
    ...>           {:tuple,
    ...>            [
    ...>              %{name: "e", type: {:uint, 96}},
    ...>              %{name: "f", type: :address},
    ...>              %{name: "g", type: :bytes},
    ...>              %{name: "h", type: :bytes},
    ...>              %{name: "i", type: {:uint, 256}}
    ...>            ]}
    ...>       },
    ...>       %{name: "j", type: {:uint, 8}},
    ...>       %{name: "k", type: {:bytes, 32}},
    ...>       %{name: "l", type: {:bytes, 32}}
    ...>     ],
    ...>     returns: [%{name: "", type: :bytes}]
    ...>   }
    ...> )
    ...> |> Base.encode16(case: :lower)
    "19c9d90a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000010600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007"

    iex> [%{x: 42, flag: true}]
    ...> |> ABI.TypeEncoder.encode(
    ...>      %ABI.FunctionSelector{
    ...>        function: nil,
    ...>        types: [
    ...>          %{type: {:tuple, [
    ...>            %{name: "x", type: {:uint, 32}},
    ...>            %{name: "flag", type: :bool}
    ...>          ]}}
    ...>        ]
    ...>      }
    ...>    )
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000001"

    iex> [-255]
    ...> |> ABI.TypeEncoder.encode(%ABI.FunctionSelector{function: nil, types: [%{type: {:int, 16}}]})
    ...> |> Base.encode16(case: :lower)
    "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01"

# `encode_packed`

```elixir
@spec encode_packed([any()], [ABI.FunctionSelector.argument_type()]) :: binary()
```

Encodes a list of values using Solidity's
[non-standard packed mode](https://docs.soliditylang.org/en/stable/abi-spec.html#non-standard-packed-mode).

Used primarily for `keccak256(abi.encodePacked(...))` Merkle leaves and
signature schemes; never used for actual function calls (the spec defines
no decoding function — encoding is ambiguous with multiple dynamic args).

Tuple/struct values and nested arrays raise `ArgumentError` — Solidity's
spec does not define their packed encoding.

## Examples

    iex> ABI.TypeEncoder.encode_packed(
    ...>   [-1, <<0x42>>, 3, "Hello, world!"],
    ...>   [
    ...>     %{type: {:int, 16}},
    ...>     %{type: {:bytes, 1}},
    ...>     %{type: {:uint, 16}},
    ...>     %{type: :string}
    ...>   ]
    ...> ) |> Base.encode16(case: :lower)
    "ffff42000348656c6c6f2c20776f726c6421"

# `encode_raw`

```elixir
@spec encode_raw([any()], [ABI.FunctionSelector.argument_type()]) :: binary()
```

Simiar to `ABI.TypeEncoder.encode/2` except we accept
an array of types instead of a function selector. We also
do not pre-pend the method id.

## Examples

    iex> [{"awesome", true}]
    ...> |> ABI.TypeEncoder.encode_raw([%{type: {:tuple, [%{type: :string}, %{type: :bool}]}}])
    ...> |> Base.encode16(case: :lower)
    "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007617765736f6d6500000000000000000000000000000000000000000000000000"

---

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