ABI.TypeDecoder is responsible for decoding types to the format
expected by Solidity. We generally take a function selector and binary
data and decode that into the original arguments according to the
specification.
Summary
Functions
Decodes the given data based on the function selector.
Reads size_in_bytes of content out of data, skipping the 32-byte-slot
padding on whichever side matches padding_direction (:left for
left-padded types like address and uint/int, :right for
right-padded types like bytes<M> and string). Returns {value, rest}.
Similar to ABI.TypeDecoder.decode/2 except accepts a list of types instead
of a function selector.
Combines a list of ABI argument types with a list of decoded element values
into either a tuple or (when decode_structs is true and every type carries
a non-empty :name) a map keyed by String.to_atom(Macro.underscore(name)).
Functions
@spec decode(binary(), ABI.FunctionSelector.t(), keyword()) :: [any()]
Decodes the given data based on the function selector.
Note, we don't currently try to guess the function name?
Examples
iex> "00000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: "baz",
...> types: [
...> %{type: {:uint, 32}},
...> %{type: :bool}
...> ],
...> returns: :bool
...> }
...> )
[69, true]
iex> "000000000000000000000000000000000000000000000000000000000000000b68656c6c6f20776f726c64000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: :string}
...> ]
...> }
...> )
["hello world"]
iex> "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:tuple, [%{type: {:uint, 32}, name: "a"}, %{type: :bool, name: "b"}]}}
...> ]
...> }
...> )
[{17, true}]
iex> "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:tuple, [%{type: {:uint, 32}, name: "a"}, %{type: :bool, name: "b"}]}}
...> ]
...> },
...> decode_structs: true
...> )
[%{a: 17, b: true}]
iex> "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:tuple, [%{type: {:uint, 32}}, %{type: :bool}]}}
...> ]
...> }
...> )
[{17, true}]
iex> "00000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:array, {:uint, 32}, 2}}
...> ]
...> }
...> )
[[17, 1]]
iex> "000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:array, {:uint, 32}}}
...> ]
...> }
...> )
[[17, 1]]
iex> "0000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000011020000000000000000000000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:array, {:uint, 32}, 2}},
...> %{type: :bool},
...> %{type: {:bytes, 2}}
...> ]
...> }
...> )
[[17, 1], true, <<16, 32>>]
iex> "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007617765736f6d6500000000000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:tuple, [%{type: :string}, %{type: :bool}]}}
...> ]
...> }
...> )
[{"awesome", true}]
iex> "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [
...> %{type: {:tuple, [%{type: {:array, :address}}]}}
...> ]
...> }
...> )
[{[]}]
iex> "00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c556e617574686f72697a656400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000204a2bf2ff0a4eaf1890c8d8679eaa446fb852c4000000000000000000000000861d9af488d5fa485bb08ab6912fff4f7450849a"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: nil,
...> types: [%{type: {:tuple,[
...> %{type: :string},
...> %{type: {:array, {:uint, 256}}}
...> ]}}]
...> }
...> )
[{
"Unauthorized",
[
184341788326688649239867304918349890235378717380,
765664983403968947098136133435535343021479462042,
]
}]
iex> "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034241540000000000000000000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode(
...> %ABI.FunctionSelector{
...> function: "price",
...> types: [
...> %{type: :string}
...> ],
...> returns: {:uint, 256}
...> }
...> )
["BAT"]
Reads size_in_bytes of content out of data, skipping the 32-byte-slot
padding on whichever side matches padding_direction (:left for
left-padded types like address and uint/int, :right for
right-padded types like bytes<M> and string). Returns {value, rest}.
@spec decode_raw(binary(), [ABI.FunctionSelector.argument_type()], keyword()) :: [ any() ]
Similar to ABI.TypeDecoder.decode/2 except accepts a list of types instead
of a function selector.
Examples
iex> "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000007617765736f6d6500000000000000000000000000000000000000000000000000"
...> |> Base.decode16!(case: :lower)
...> |> ABI.TypeDecoder.decode_raw([%{type: {:tuple, [%{type: :string}, %{type: :bool}]}}])
[{"awesome", true}]
@spec tuple_value([ABI.FunctionSelector.argument_type()], [any()], boolean()) :: map() | tuple()
Combines a list of ABI argument types with a list of decoded element values
into either a tuple or (when decode_structs is true and every type carries
a non-empty :name) a map keyed by String.to_atom(Macro.underscore(name)).
Used internally by decode_type({:tuple, types}, ...) to render the
second-pass result; exposed because event-log decoding in ABI.Event
reuses the same shape.