@@ -8,6 +8,8 @@ defmodule ABI do
88 @ doc """
99 Encodes the given data into the function signature or tuple signature.
1010
11+ In place of a signature, you can also pass one of the `ABI.FunctionSelector` structs returned from `parse_specification/1`.
12+
1113 ## Examples
1214
1315 iex> ABI.encode("baz(uint,address)", [50, <<1::160>> |> :binary.decode_unsigned])
@@ -24,18 +26,28 @@ defmodule ABI do
2426 iex> ABI.encode("(string)", [{"Ether Token"}])
2527 ...> |> Base.encode16(case: :lower)
2628 "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b457468657220546f6b656e000000000000000000000000000000000000000000"
29+
30+ iex> File.read!("priv/dog.abi.json")
31+ ...> |> Poison.decode!
32+ ...> |> ABI.parse_specification
33+ ...> |> Enum.find(&(&1.function == "bark")) # bark(address,bool)
34+ ...> |> ABI.encode([<<1::160>> |> :binary.decode_unsigned, true])
35+ ...> |> Base.encode16(case: :lower)
36+ "b85d0bd200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"
2737 """
28- def encode ( function_signature , data ) do
29- ABI.TypeEncoder . encode (
30- data ,
31- ABI.FunctionSelector . decode ( function_signature )
32- )
38+ def encode ( function_signature , data ) when is_binary ( function_signature ) do
39+ encode ( ABI.Parser . parse! ( function_signature ) , data )
40+ end
41+ def encode ( % ABI.FunctionSelector { } = function_selector , data ) do
42+ ABI.TypeEncoder . encode ( data , function_selector )
3343 end
3444
3545 @ doc """
3646 Decodes the given data based on the function or tuple
3747 signature.
3848
49+ In place of a signature, you can also pass one of the `ABI.FunctionSelector` structs returned from `parse_specification/1`.
50+
3951 ## Examples
4052
4153 iex> ABI.decode("baz(uint,address)", "00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001" |> Base.decode16!(case: :lower))
@@ -46,12 +58,73 @@ defmodule ABI do
4658
4759 iex> ABI.decode("(string)", "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000b457468657220546f6b656e000000000000000000000000000000000000000000" |> Base.decode16!(case: :lower))
4860 [{"Ether Token"}]
61+
62+ iex> File.read!("priv/dog.abi.json")
63+ ...> |> Poison.decode!
64+ ...> |> ABI.parse_specification
65+ ...> |> Enum.find(&(&1.function == "bark")) # bark(address,bool)
66+ ...> |> ABI.decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001" |> Base.decode16!(case: :lower))
67+ [<<1::160>>, true]
4968 """
50- def decode ( function_signature , data ) do
51- ABI.TypeDecoder . decode (
52- data ,
53- ABI.FunctionSelector . decode ( function_signature )
54- )
69+ def decode ( function_signature , data ) when is_binary ( function_signature ) do
70+ decode ( ABI.Parser . parse! ( function_signature ) , data )
71+ end
72+ def decode ( % ABI.FunctionSelector { } = function_selector , data ) do
73+ ABI.TypeDecoder . decode ( data , function_selector )
5574 end
5675
76+ @ doc """
77+ Parses the given ABI specification document into an array of `ABI.FunctionSelector`s.
78+
79+ Non-function entries (e.g. constructors) in the ABI specification are skipped. Fallback function entries are accepted.
80+
81+ This function can be used in combination with a JSON parser, e.g. [`Poison`](https://hex.pm/packages/poison), to parse ABI specification JSON files.
82+
83+ ## Examples
84+
85+ iex> File.read!("priv/dog.abi.json")
86+ ...> |> Poison.decode!
87+ ...> |> ABI.parse_specification
88+ [%ABI.FunctionSelector{function: "bark", returns: nil, types: [:address, :bool]},
89+ %ABI.FunctionSelector{function: "rollover", returns: :bool, types: []}]
90+
91+ iex> [%{
92+ ...> "constant" => true,
93+ ...> "inputs" => [
94+ ...> %{"name" => "at", "type" => "address"},
95+ ...> %{"name" => "loudly", "type" => "bool"}
96+ ...> ],
97+ ...> "name" => "bark",
98+ ...> "outputs" => [],
99+ ...> "payable" => false,
100+ ...> "stateMutability" => "nonpayable",
101+ ...> "type" => "function"
102+ ...> }]
103+ ...> |> ABI.parse_specification
104+ [%ABI.FunctionSelector{function: "bark", returns: nil, types: [:address, :bool]}]
105+
106+ iex> [%{
107+ ...> "inputs" => [
108+ ...> %{"name" => "_numProposals", "type" => "uint8"}
109+ ...> ],
110+ ...> "payable" => false,
111+ ...> "stateMutability" => "nonpayable",
112+ ...> "type" => "constructor"
113+ ...> }]
114+ ...> |> ABI.parse_specification
115+ []
116+
117+ iex> [%{
118+ ...> "payable" => false,
119+ ...> "stateMutability" => "nonpayable",
120+ ...> "type" => "fallback"
121+ ...> }]
122+ ...> |> ABI.parse_specification
123+ [%ABI.FunctionSelector{function: nil, returns: nil, types: []}]
124+ """
125+ def parse_specification ( doc ) do
126+ doc
127+ |> Enum . map ( & ABI.FunctionSelector . parse_specification_item / 1 )
128+ |> Enum . filter ( & ( & 1 ) )
129+ end
57130end
0 commit comments