Search documentation of Cartouche

# Cartouche.Hex (Cartouche v0.1.3)

Copy Markdown View Source

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.

## Summary

### Types

t()

### Functions

checksum_address(address)

Checksums an Ethereum address per EIP-55.

decode_address!(hex)

Parses an Ethereum 20-bytes hex string.

decode_hex(b)

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

decode_hex!(b)

Parses a hex string and raises if invalid.

decode_hex_input!(hex)

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

decode_hex_number(b)

Parses hex value as a big-endian integer.

decode_hex_number!(b)

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

decode_maybe_hex!(h)

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

decode_sized!(hex, sz, msg \\ nil)

Parses an Ethereum x-bytes hex string.

decode_word!(hex)

Parses an Ethereum 32-bytes hex string.

encode_address(b)

Encodes a binary as a checksummed Ethereum address.

encode_big_hex(hex)

Encodes hex, in CAPITALS.

encode_bytes(b, size)

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

encode_hex(b)

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

encode_hex_result(els)

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

encode_quantity(n)

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

encode_short_hex(hex)

Encodes hex, striping any leading zeros.

from_hex(b)

Alias for `decode_hex`.

from_hex!(b)

Alias for `decode_hex!`.

hex!(hex_str)

Similar non-sigil compile-time hex parser.

maybe_encode_hex(b)

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

nibbles(v)

Returns the nibbles of a binary as a list.

pad(bin, size)

Pads a binary to a given length.

sigil_h(term, modifiers)

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

to_address(b)

Alias for `encode_address`.

to_hex(b)

Alias for `encode_hex`.

## Types

# t()

    @type t() :: binary()

## Functions

# checksum_address(address)

    @spec checksum_address(String.t() | <<_::160>>) :: String.t()

Checksums an Ethereum address per EIP-55.

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!(hex)

    @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(b)

    @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!(b)

    @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!(hex)

    @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(b)

    @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!(b)

    @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!(h)

    @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_sized!(hex, sz, msg \\ nil)

    @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!(hex)

    @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(b)

    @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(hex)

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

Encodes hex, in CAPITALS.

## Examples

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

# encode_bytes(b, size)

    @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(b)

    @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(els)

    @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(n)

    @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(hex)

    @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(b)

    @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!(b)

    @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!(hex_str)

(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(b)

    @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(v)

    @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(bin, size)

    @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(term, modifiers)

(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(b)

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

Alias for `encode_address`.

## Examples

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

# to_hex(b)

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

Alias for `encode_hex`.

## Examples

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