# `Cartouche.Hex`
[🔗](https://github.com/zenhive/cartouche/blob/main/lib/cartouche/hex.ex#L1)

Helper module for parsing and encoding hex values.

If you `use Cartouche.Hex`, then you can use the `~h` sigil for compile-time
hex-to-binary compilation.

# `t`

```elixir
@type t() :: binary()
```

# `checksum_address`

```elixir
@spec checksum_address(String.t() | &lt;&lt;_::160&gt;&gt;) :: String.t()
```

Checksums an Ethereum address per [EIP-55](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md).

The result is a string-encoded (mixed-case) version of the address.

## Examples

    iex> Cartouche.Hex.checksum_address("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
    "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed"

    iex> Cartouche.Hex.checksum_address("0xFB6916095CA1DF60BB79CE92CE3EA74C37C5D359")
    "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359"

    iex> Cartouche.Hex.checksum_address("0xdbf03b407c01e7cd3cbea99509d93f8dddc8c6fb")
    "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB"

    iex> Cartouche.Hex.checksum_address("0xd1220a0cf47c7b9be7a2e6ba89f429762e7b9adb")
    "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb"

# `decode_address!`

```elixir
@spec decode_address!(String.t()) :: t() | no_return()
```

Parses an Ethereum 20-bytes hex string.

Identical to `decode_hex!/1` except fails if
string is not exactly 20-bytes.

## Examples

  iex> Cartouche.Hex.decode_address!("0x0000000000000000000000000000000000000001")
  <<1::160>>

  iex> Cartouche.Hex.decode_address!("0xaabb")
  ** (Cartouche.Hex.InvalidHex) invalid hex address: "0xaabb"

# `decode_hex`

```elixir
@spec decode_hex(String.t()) :: {:ok, t()} | :invalid_hex
```

Parses a hex string, but returns `:error` instead
of raising if hex is invalid.

## Examples

    iex> Cartouche.Hex.decode_hex("0xaabb")
    {:ok, <<170, 187>>}

    iex> Cartouche.Hex.decode_hex("aabb")
    {:ok, <<170, 187>>}

    iex> Cartouche.Hex.decode_hex("0xgggg")
    :invalid_hex

# `decode_hex!`

```elixir
@spec decode_hex!(String.t()) :: t()
```

Parses a hex string and raises if invalid.

## Examples

  iex> Cartouche.Hex.decode_hex!("aabb")
  <<170, 187>>

  iex> Cartouche.Hex.decode_hex!("0xggaabb")
  ** (Cartouche.Hex.InvalidHex) invalid hex: "0xggaabb"

# `decode_hex_input!`

```elixir
@spec decode_hex_input!(String.t() | binary()) :: t()
```

Decodes hex, allowing it to either be `"0x..."` or a raw binary.

Note: a hex-printed string, in this case, must start with `0x`,
      otherwise it will be interpreted as its ASCII values.

## Examples

    iex> Cartouche.Hex.decode_hex_input!("0x55")
    <<0x55>>

    iex> Cartouche.Hex.decode_hex_input!(<<0x55>>)
    <<0x55>>

# `decode_hex_number`

```elixir
@spec decode_hex_number(String.t()) :: {:ok, integer()} | :invalid_hex
```

Parses hex value as a big-endian integer.

## Examples

    iex> Cartouche.Hex.decode_hex_number("0xaabb")
    {:ok, 0xaabb}

    iex> Cartouche.Hex.decode_hex_number("0xgggg")
    :invalid_hex

# `decode_hex_number!`

```elixir
@spec decode_hex_number!(String.t()) :: integer() | no_return()
```

Parses hex value as a big-endian integer. Raises if invalid.

## Examples

  iex> Cartouche.Hex.decode_hex_number!("0xaabb")
  0xaabb

  iex> Cartouche.Hex.decode_hex_number!("0xgggg")
  ** (Cartouche.Hex.InvalidHex) invalid hex number: "0xgggg"

# `decode_maybe_hex!`

```elixir
@spec decode_maybe_hex!(String.t() | nil) :: t() | nil
```

Parses hex is value is not nil, otherwise returns `nil`.

## Examples

  iex> Cartouche.Hex.decode_maybe_hex!("0xaabb")
  <<170, 187>>

  iex> Cartouche.Hex.decode_maybe_hex!(nil)
  nil

# `decode_maybe_hex_number!`

```elixir
@spec decode_maybe_hex_number!(String.t() | nil) :: integer() | nil | no_return()
```

Parses a hex value as a big-endian integer if not nil, otherwise returns `nil`.

Useful for JSON-RPC fields that are absent on pre-fork blocks (e.g.
`blobGasUsed` / `blobGasPrice` on pre-Cancun receipts).

## Examples

  iex> Cartouche.Hex.decode_maybe_hex_number!("0xaabb")
  0xaabb

  iex> Cartouche.Hex.decode_maybe_hex_number!(nil)
  nil

# `decode_sized!`

```elixir
@spec decode_sized!(String.t(), integer(), String.t() | nil) :: t() | no_return()
```

Parses an Ethereum x-bytes hex string.

Identical to `decode_hex!/1` except fails if
string is not exactly x-bytes.

## Examples

  iex> Cartouche.Hex.decode_sized!("0x001122", 3)
  <<0x00, 0x11, 0x22>>

  iex> Cartouche.Hex.decode_sized!("0xaabb", 3)
  ** (Cartouche.Hex.InvalidHex) invalid 3-byte sized hex: "0xaabb"

# `decode_word!`

```elixir
@spec decode_word!(String.t()) :: t() | no_return()
```

Parses an Ethereum 32-bytes hex string.

Identical to `decode_hex!/1` except fails if
string is not exactly 32-bytes.

## Examples

  iex> Cartouche.Hex.decode_word!("0x0000000000000000000000000000000000000000000000000000000000000001")
  <<1::256>>

  iex> Cartouche.Hex.decode_word!("0xaabb")
  ** (Cartouche.Hex.InvalidHex) invalid hex word: "0xaabb"

# `encode_address`

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

Encodes a binary as a checksummed Ethereum address.

## Examples

  iex> Cartouche.Hex.encode_address(<<0xaa, 0xbb, 0xcc, 0::136>>)
  "0xaABbcC0000000000000000000000000000000000"

  iex> Cartouche.Hex.encode_address(<<55>>)
  ** (Cartouche.Hex.InvalidHex) Expected 20-byte address for in `Cartouche.Hex.encode_address/1`

# `encode_big_hex`

```elixir
@spec encode_big_hex(binary()) :: String.t()
```

Encodes hex, in CAPITALS.

## Examples

  iex> Cartouche.Hex.encode_big_hex(<<0xcc, 0xdd>>)
  "0xCCDD"

# `encode_bytes`

```elixir
@spec encode_bytes(integer() | nil, pos_integer()) :: binary() | nil
```

Encodes a number as a binary of a fixed byte length, left-padded with zeros.

## Examples

    iex> Cartouche.Hex.encode_bytes(257, 4)
    <<0, 0, 1, 1>>

    iex> Cartouche.Hex.encode_bytes(nil, 4)
    nil

# `encode_hex`

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

Encodes a given value as a lowercase hex string, starting with `0x`.

## Examples

  iex> Cartouche.Hex.encode_hex(<<0xaa, 0xbb>>)
  "0xaabb"

# `encode_hex_result`

```elixir
@spec encode_hex_result({:ok, t()} | term()) :: {:ok, String.t()} | term()
```

If input is a tuple `{:ok, x}` then returns a tuple `{:ok, hex}`
where `hex = encode(x)`. Otherwise, returns its input unchanged.

## Examples

    iex> Cartouche.Hex.encode_hex_result({:ok, <<0xaa, 0xbb>>})
    {:ok, "0xaabb"}

    iex> Cartouche.Hex.encode_hex_result({:error, 55})
    {:error, 55}

# `encode_quantity`

```elixir
@spec encode_quantity(non_neg_integer()) :: String.t()
```

Encodes a non-negative integer as a JSON-RPC "quantity" string.

Lowercase hex with `0x` prefix and no leading zeros. `0` becomes `"0x0"`.

This matches the JSON-RPC spec for the `QUANTITY` type used in
`eth_getBlockByNumber`, `eth_getBalance`, `eth_call` block params, etc.

## Examples

    iex> Cartouche.Hex.encode_quantity(0)
    "0x0"

    iex> Cartouche.Hex.encode_quantity(55)
    "0x37"

    iex> Cartouche.Hex.encode_quantity(24_975_978)
    "0x17d1a6a"

# `encode_short_hex`

```elixir
@spec encode_short_hex(binary() | integer()) :: String.t()
```

Encodes hex, striping any leading zeros.

## Examples

  iex> Cartouche.Hex.encode_short_hex(<<0xc>>)
  "0xC"

  iex> Cartouche.Hex.encode_short_hex(12)
  "0xC"

  iex> Cartouche.Hex.encode_short_hex(<<0x0>>)
  "0x0"

# `from_hex`

```elixir
@spec from_hex(String.t()) :: {:ok, t()} | :invalid_hex
```

Alias for `decode_hex`.

## Examples

    iex> Cartouche.Hex.from_hex("0xaabb")
    {:ok, <<0xaa, 0xbb>>}

    iex> Cartouche.Hex.from_hex("0xgggg")
    :invalid_hex

# `from_hex!`

```elixir
@spec from_hex!(String.t()) :: t()
```

Alias for `decode_hex!`.

## Examples

  iex> Cartouche.Hex.from_hex!("0xaabb")
  <<0xaa, 0xbb>>

  iex> Cartouche.Hex.from_hex!("0xggaabb")
  ** (Cartouche.Hex.InvalidHex) invalid hex: "0xggaabb"

# `hex!`
*macro* 

Similar non-sigil compile-time hex parser.

## Examples

    iex> use Cartouche.Hex
    iex> hex!("0x22")
    <<0x22>>

    iex> use Cartouche.Hex
    iex> hex!("0x2244")
    <<0x22, 0x44>>

# `maybe_encode_hex`

```elixir
@spec maybe_encode_hex(t() | nil) :: String.t() | nil
```

If input is non-`nil`, returns input encoded as a hex string. Otherwise,
returns `nil`.

## Examples

  iex> Cartouche.Hex.maybe_encode_hex(<<0xaa, 0xbb>>)
  "0xaabb"

  iex> Cartouche.Hex.maybe_encode_hex(nil)
  nil

# `nibbles`

```elixir
@spec nibbles(binary()) :: [0..15]
```

Returns the nibbles of a binary as a list.

## Examples

    iex> Cartouche.Hex.nibbles(<<0xF5, 0xE6, 0xD0>>)
    [0xF, 0x5, 0xE, 0x6, 0xD, 0x0]

# `pad`

```elixir
@spec pad(binary(), pos_integer()) :: binary()
```

Pads a binary to a given length.

## Examples

    iex> Cartouche.Hex.pad(<<1, 2>>, 2)
    <<1, 2>>

    iex> Cartouche.Hex.pad(<<1, 2>>, 4)
    <<0, 0, 1, 2>>

    iex> Cartouche.Hex.pad(<<1, 2>>, 1)
    ** (FunctionClauseError) no function clause matching in Cartouche.Hex.pad/2

# `sigil_h`
*macro* 

Handles the sigil `~h` for list of words.

Parses a hex string at compile-time.

## Examples

    iex> use Cartouche.Hex
    iex> ~h[0x22]
    <<0x22>>

    iex> use Cartouche.Hex
    iex> ~h[0x2244]
    <<0x22, 0x44>>

# `to_address`

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

Alias for `encode_address`.

## Examples

  iex> Cartouche.Hex.to_address(<<0xaa, 0xbb, 0xcc, 0::136>>)
  "0xaABbcC0000000000000000000000000000000000"

# `to_hex`

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

Alias for `encode_hex`.

## Examples

  iex> Cartouche.Hex.to_hex(<<0xaa, 0xbb>>)
  "0xaabb"

---

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