# `EEVM.ABI`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/abi.ex#L1)

Encodes and decodes Solidity ABI data: calldata for a function call,
return data, and event logs, as the
[Solidity ABI specification](https://docs.soliditylang.org/en/latest/abi-spec.html)
defines them.

    iex> calldata = EEVM.ABI.encode_call("transfer(address,uint256)", [0xB0B, 250])
    iex> byte_size(calldata)
    68
    iex> EEVM.ABI.decode(["bool"], <<1::256>>)
    {:ok, [true]}

Types are Solidity type strings, such as `"uint256"`, `"address[]"`, or
`"(uint256,bytes)[2]"` for a fixed-size array of tuples. Signatures may
carry parameter names and spaces, as in Solidity source, and `uint` and
`int` mean `uint256` and `int256`; selectors and event topics are always
computed from the canonical form, so `"transfer(address to, uint amount)"`
encodes the same calldata as `"transfer(address,uint256)"`.

## Values

| ABI type | Elixir value |
|----------|--------------|
| `uint<N>`, `int<N>` | integer |
| `address` | integer, as eevm represents addresses; encoding also takes anything `EEVM.address/1` takes |
| `bool` | `true` or `false` |
| `bytes<N>` | binary of exactly `N` bytes |
| `bytes`, `string` | binary |
| `T[]`, `T[k]` | list |
| `(T1,T2,...)` | tuple |

`fixed`, `ufixed`, and `function` types are not supported.

## Errors

Following eevm's error rule, encoding raises `ArgumentError` for an
unknown type or a value that doesn't fit its type, since both are mistakes
in the caller's code. Decoding returns `{:error, :invalid_abi_data}` for
data that doesn't match its types, since return data and logs come from
contracts. Like Solidity's own decoder, decoding is strict: an integer,
address, `bool`, or `bytes<N>` word with bits outside its type, or an
offset or length past the end of the data, is an error rather than being
masked or truncated. Bytes after the encoded values are ignored.

Decoding work is capped at 16 times the size of the data, which is far
more than any canonical encoding needs. Crafted offsets that point many
values at the same bytes, which would make decoding take time quadratic
in the input size, fail with `{:error, :invalid_abi_data}` instead.

# `log`

```elixir
@type log() :: %{
  :topics =&gt; [non_neg_integer()],
  :data =&gt; binary(),
  optional(atom()) =&gt; term()
}
```

An event log, as in `result.logs`: topics are integers.

# `value`

```elixir
@type value() :: integer() | boolean() | binary() | [value()] | tuple()
```

An Elixir value for an ABI type; see the table in the module docs.

# `decode`

```elixir
@spec decode([String.t()], binary()) :: {:ok, [value()]} | {:error, :invalid_abi_data}
```

Decodes ABI-encoded `data`, such as a call's `return_data`, as values of
`types`. Returns `{:ok, values}`, one value per type.

Returns `{:error, :invalid_abi_data}` when `data` doesn't hold valid
values of `types`, and raises `ArgumentError` for an unknown type.

## Examples

    iex> EEVM.ABI.decode(["uint256"], <<1000::256>>)
    {:ok, [1000]}

    iex> data = EEVM.ABI.encode(["int8", "string", "uint16[]"], [-1, "eevm", [1, 2]])
    iex> EEVM.ABI.decode(["int8", "string", "uint16[]"], data)
    {:ok, [-1, "eevm", [1, 2]]}

    iex> EEVM.ABI.decode(["uint8"], <<256::256>>)
    {:error, :invalid_abi_data}

# `decode_log`

```elixir
@spec decode_log(String.t(), log()) ::
  {:ok, [value()]} | {:error, :event_mismatch | :invalid_abi_data}
```

Decodes an event `log`, such as an entry of `result.logs`, as the event
`signature`, which marks indexed parameters with `indexed` as Solidity
does. Returns `{:ok, values}` with every parameter's value in declaration
order.

An indexed `uint`, `int`, `address`, `bool`, or `bytes<N>` parameter
decodes to its value. Any other indexed parameter (`bytes`, `string`,
arrays, tuples) decodes to its topic's 32 bytes, the Keccak-256 hash of
its encoding, since the log doesn't hold the value itself.

Returns `{:error, :event_mismatch}` when the log's first topic isn't the
event's topic or its topic count doesn't match the indexed parameters (so
you can try a log against several events), and
`{:error, :invalid_abi_data}` when the log is that event but its data or
topics don't decode. Anonymous events, which have no event topic, aren't
supported.

## Example

    iex> log = %{
    ...>   address: 0x7070,
    ...>   topics: [EEVM.event_topic("Transfer(address,address,uint256)"), 0xA11CE, 0xB0B],
    ...>   data: <<250::256>>
    ...> }
    iex> EEVM.ABI.decode_log("Transfer(address indexed from, address indexed to, uint256 value)", log)
    {:ok, [0xA11CE, 0xB0B, 250]}
    iex> EEVM.ABI.decode_log("Approval(address indexed,address indexed,uint256)", log)
    {:error, :event_mismatch}

# `encode`

```elixir
@spec encode([String.t()], [value()]) :: binary()
```

ABI-encodes `values` as the arguments of a function with parameter
`types`, without a selector: the encoding of the tuple of the values.

Raises `ArgumentError` for an unknown type, a wrong number of values, or a
value that doesn't fit its type.

## Examples

    iex> EEVM.ABI.encode(["uint32", "bool"], [69, true]) |> EEVM.hex()
    "0x" <> String.pad_leading("45", 64, "0") <> String.pad_leading("1", 64, "0")

    iex> EEVM.ABI.encode(["string"], ["hi"]) |> byte_size()
    96

# `encode_call`

```elixir
@spec encode_call(String.t(), [value()]) :: binary()
```

Builds calldata for a call to the function `signature` with `args`: its
4-byte selector followed by the ABI-encoded arguments. Pass the result to
`EEVM.call/4` or as a transaction's `data`.

Raises `ArgumentError` for a malformed signature, a wrong number of
arguments, or an argument that doesn't fit its type.

## Examples

    iex> calldata = EEVM.ABI.encode_call("balanceOf(address)", [0xA11CE])
    iex> EEVM.hex(calldata)
    "0x70a08231" <> String.duplicate("0", 59) <> "a11ce"

    iex> EEVM.ABI.encode_call("transfer(address to, uint amount)", [0xB0B, 1]) ==
    ...>   EEVM.ABI.encode_call("transfer(address,uint256)", [0xB0B, 1])
    true

---

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