mirror of https://github.com/poanetwork/ex_abi.git
format code
This commit is contained in:
parent
d6ccbf0bf3
commit
929ba1570d
|
@ -0,0 +1,5 @@
|
|||
[
|
||||
inputs: [
|
||||
"{lib,config,test}/**/*.{ex,exs}"
|
||||
]
|
||||
]
|
|
@ -1,7 +0,0 @@
|
|||
Copyright 2018 Geoffrey Hayes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
10
README.md
10
README.md
|
@ -1,16 +1,16 @@
|
|||
# ABI
|
||||
# ExABI
|
||||
|
||||
The [Application Binary Interface](https://solidity.readthedocs.io/en/develop/abi-spec.html) (ABI) of Solidity describes how to transform binary data to types which the Solidity programming language understands. For instance, if we want to call a function `bark(uint32,bool)` on a Solidity-created contract `contract Dog`, what `data` parameter do we pass into our Ethereum transaction? This project allows us to encode such function calls.
|
||||
|
||||
## Installation
|
||||
|
||||
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||
by adding `abi` to your list of dependencies in `mix.exs`:
|
||||
by adding `ex_abi` to your list of dependencies in `mix.exs`:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:abi, "~> 0.1.8"}
|
||||
{:ex_abi, "~> 0.1.12"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
@ -77,7 +77,3 @@ Currently supports:
|
|||
* [Solidity Docs](https://solidity.readthedocs.io/)
|
||||
* [Solidity Grammar](https://github.com/ethereum/solidity/blob/develop/docs/grammar.txt)
|
||||
* [Exthereum Blockchain](https://github.com/exthereum/blockchain)
|
||||
|
||||
# Collaboration
|
||||
|
||||
This ABI library is licensed under the MIT license. Feel free to submit issues, pull requests or fork the code as you wish.
|
||||
|
|
|
@ -38,6 +38,7 @@ defmodule ABI do
|
|||
def encode(function_signature, data) when is_binary(function_signature) do
|
||||
encode(ABI.Parser.parse!(function_signature), data)
|
||||
end
|
||||
|
||||
def encode(%ABI.FunctionSelector{} = function_selector, data) do
|
||||
ABI.TypeEncoder.encode(data, function_selector)
|
||||
end
|
||||
|
@ -69,6 +70,7 @@ defmodule ABI do
|
|||
def decode(function_signature, data) when is_binary(function_signature) do
|
||||
decode(ABI.Parser.parse!(function_signature), data)
|
||||
end
|
||||
|
||||
def decode(%ABI.FunctionSelector{} = function_selector, data) do
|
||||
ABI.TypeDecoder.decode(data, function_selector)
|
||||
end
|
||||
|
@ -125,6 +127,6 @@ defmodule ABI do
|
|||
def parse_specification(doc) do
|
||||
doc
|
||||
|> Enum.map(&ABI.FunctionSelector.parse_specification_item/1)
|
||||
|> Enum.filter(&(&1))
|
||||
|> Enum.filter(& &1)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,20 +7,20 @@ defmodule ABI.FunctionSelector do
|
|||
require Integer
|
||||
|
||||
@type type ::
|
||||
{:uint, integer()} |
|
||||
:bool |
|
||||
:bytes |
|
||||
:string |
|
||||
:address |
|
||||
{:array, type} |
|
||||
{:array, type, non_neg_integer} |
|
||||
{:tuple, [type]}
|
||||
{:uint, integer()}
|
||||
| :bool
|
||||
| :bytes
|
||||
| :string
|
||||
| :address
|
||||
| {:array, type}
|
||||
| {:array, type, non_neg_integer}
|
||||
| {:tuple, [type]}
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
function: String.t,
|
||||
types: [type],
|
||||
returns: type
|
||||
}
|
||||
function: String.t(),
|
||||
types: [type],
|
||||
returns: type
|
||||
}
|
||||
|
||||
defstruct [:function, :types, :returns]
|
||||
|
||||
|
@ -129,6 +129,7 @@ defmodule ABI.FunctionSelector do
|
|||
returns: List.first(output_types)
|
||||
}
|
||||
end
|
||||
|
||||
def parse_specification_item(%{"type" => "fallback"}) do
|
||||
%ABI.FunctionSelector{
|
||||
function: nil,
|
||||
|
@ -136,6 +137,7 @@ defmodule ABI.FunctionSelector do
|
|||
returns: nil
|
||||
}
|
||||
end
|
||||
|
||||
def parse_specification_item(_), do: nil
|
||||
|
||||
defp parse_specification_type(%{"type" => type}), do: decode_type(type)
|
||||
|
@ -208,15 +210,14 @@ defmodule ABI.FunctionSelector do
|
|||
"(#{Enum.join(encoded_types, ",")})"
|
||||
end
|
||||
|
||||
defp get_type(els), do: raise "Unsupported type: #{inspect els}"
|
||||
defp get_type(els), do: raise("Unsupported type: #{inspect(els)}")
|
||||
|
||||
@doc false
|
||||
@spec is_dynamic?(ABI.FunctionSelector.type) :: boolean
|
||||
@spec is_dynamic?(ABI.FunctionSelector.type()) :: boolean
|
||||
def is_dynamic?(:bytes), do: true
|
||||
def is_dynamic?(:string), do: true
|
||||
def is_dynamic?({:array, _type}), do: true
|
||||
def is_dynamic?({:array, type, len}) when len > 0, do: is_dynamic?(type)
|
||||
def is_dynamic?({:tuple, types}), do: Enum.any?(types, &is_dynamic?/1)
|
||||
def is_dynamic?(_), do: false
|
||||
|
||||
end
|
||||
|
|
|
@ -3,13 +3,14 @@ defmodule ABI.Parser do
|
|||
|
||||
@doc false
|
||||
def parse!(str, opts \\ []) do
|
||||
{:ok, tokens, _} = str |> String.to_charlist |> :ethereum_abi_lexer.string
|
||||
{:ok, tokens, _} = str |> String.to_charlist() |> :ethereum_abi_lexer.string()
|
||||
|
||||
tokens = case opts[:as] do
|
||||
nil -> tokens
|
||||
:type -> [{:"expecting type", 1} | tokens]
|
||||
:selector -> [{:"expecting selector", 1} | tokens]
|
||||
end
|
||||
tokens =
|
||||
case opts[:as] do
|
||||
nil -> tokens
|
||||
:type -> [{:"expecting type", 1} | tokens]
|
||||
:selector -> [{:"expecting selector", 1} | tokens]
|
||||
end
|
||||
|
||||
{:ok, ast} = :ethereum_abi_parser.parse(tokens)
|
||||
|
||||
|
|
|
@ -151,16 +151,19 @@ defmodule ABI.TypeDecoder do
|
|||
do_decode(types, encoded_data, [])
|
||||
end
|
||||
|
||||
@spec do_decode([ABI.FunctionSelector.type], binary(), [any()]) :: [any()]
|
||||
defp do_decode([], bin, _) when byte_size(bin) > 0, do: raise("Found extra binary data: #{inspect bin}")
|
||||
@spec do_decode([ABI.FunctionSelector.type()], binary(), [any()]) :: [any()]
|
||||
defp do_decode([], bin, _) when byte_size(bin) > 0,
|
||||
do: raise("Found extra binary data: #{inspect(bin)}")
|
||||
|
||||
defp do_decode([], _, acc), do: Enum.reverse(acc)
|
||||
defp do_decode([type|remaining_types], data, acc) do
|
||||
|
||||
defp do_decode([type | remaining_types], data, acc) do
|
||||
{decoded, remaining_data} = decode_type(type, data)
|
||||
|
||||
do_decode(remaining_types, remaining_data, [decoded | acc])
|
||||
end
|
||||
|
||||
@spec decode_type(ABI.FunctionSelector.type, binary()) :: {any(), binary()}
|
||||
@spec decode_type(ABI.FunctionSelector.type(), binary()) :: {any(), binary()}
|
||||
defp decode_type({:uint, size_in_bits}, data) do
|
||||
decode_uint(data, size_in_bits)
|
||||
end
|
||||
|
@ -170,10 +173,11 @@ defmodule ABI.TypeDecoder do
|
|||
defp decode_type(:bool, data) do
|
||||
{encoded_value, rest} = decode_uint(data, 8)
|
||||
|
||||
value = case encoded_value do
|
||||
1 -> true
|
||||
0 -> false
|
||||
end
|
||||
value =
|
||||
case encoded_value do
|
||||
1 -> true
|
||||
0 -> false
|
||||
end
|
||||
|
||||
{value, rest}
|
||||
end
|
||||
|
@ -190,6 +194,7 @@ defmodule ABI.TypeDecoder do
|
|||
end
|
||||
|
||||
defp decode_type({:bytes, 0}, data), do: {<<>>, data}
|
||||
|
||||
defp decode_type({:bytes, size}, data) when size > 0 and size <= 32 do
|
||||
decode_bytes(data, size, :right)
|
||||
end
|
||||
|
@ -200,45 +205,49 @@ defmodule ABI.TypeDecoder do
|
|||
end
|
||||
|
||||
defp decode_type({:array, _type, 0}, data), do: {[], data}
|
||||
|
||||
defp decode_type({:array, type, element_count}, data) do
|
||||
repeated_type = Enum.map(1..element_count, fn _ -> type end)
|
||||
|
||||
{tuple, rest} = decode_type({:tuple, repeated_type}, data)
|
||||
|
||||
{tuple |> Tuple.to_list, rest}
|
||||
{tuple |> Tuple.to_list(), rest}
|
||||
end
|
||||
|
||||
defp decode_type({:tuple, types}, starting_data) do
|
||||
# First pass, decode static types
|
||||
{elements, rest} = Enum.reduce(types, {[], starting_data}, fn type, {elements, data} ->
|
||||
if ABI.FunctionSelector.is_dynamic?(type) do
|
||||
{tail_position, rest} = decode_type({:uint, 256}, data)
|
||||
{elements, rest} =
|
||||
Enum.reduce(types, {[], starting_data}, fn type, {elements, data} ->
|
||||
if ABI.FunctionSelector.is_dynamic?(type) do
|
||||
{tail_position, rest} = decode_type({:uint, 256}, data)
|
||||
|
||||
{[{:dynamic, type, tail_position}|elements], rest}
|
||||
else
|
||||
{el, rest} = decode_type(type, data)
|
||||
|
||||
{[el|elements], rest}
|
||||
end
|
||||
end)
|
||||
|
||||
# Second pass, decode dynamic types
|
||||
{elements, rest} = Enum.reduce(elements |> Enum.reverse, {[], rest}, fn el, {elements, data} ->
|
||||
case el do
|
||||
{:dynamic, type, _tail_position} ->
|
||||
{[{:dynamic, type, tail_position} | elements], rest}
|
||||
else
|
||||
{el, rest} = decode_type(type, data)
|
||||
|
||||
{[el|elements], rest}
|
||||
_ ->
|
||||
{[el|elements], data}
|
||||
end
|
||||
end)
|
||||
{[el | elements], rest}
|
||||
end
|
||||
end)
|
||||
|
||||
{elements |> Enum.reverse |> List.to_tuple, rest}
|
||||
# Second pass, decode dynamic types
|
||||
{elements, rest} =
|
||||
Enum.reduce(elements |> Enum.reverse(), {[], rest}, fn el, {elements, data} ->
|
||||
case el do
|
||||
{:dynamic, type, _tail_position} ->
|
||||
{el, rest} = decode_type(type, data)
|
||||
|
||||
{[el | elements], rest}
|
||||
|
||||
_ ->
|
||||
{[el | elements], data}
|
||||
end
|
||||
end)
|
||||
|
||||
{elements |> Enum.reverse() |> List.to_tuple(), rest}
|
||||
end
|
||||
|
||||
defp decode_type(els, _) do
|
||||
raise "Unsupported decoding type: #{inspect els}"
|
||||
raise "Unsupported decoding type: #{inspect(els)}"
|
||||
end
|
||||
|
||||
@spec decode_uint(binary(), integer()) :: {integer(), binary()}
|
||||
|
@ -259,11 +268,14 @@ defmodule ABI.TypeDecoder do
|
|||
|
||||
case padding_direction do
|
||||
:left ->
|
||||
<<_padding::binary-size(padding_size_in_bytes), value::binary-size(size_in_bytes), rest::binary()>> = data
|
||||
<<_padding::binary-size(padding_size_in_bytes), value::binary-size(size_in_bytes),
|
||||
rest::binary()>> = data
|
||||
|
||||
{value, rest}
|
||||
|
||||
:right ->
|
||||
<<value::binary-size(size_in_bytes), _padding::binary-size(padding_size_in_bytes), rest::binary()>> = data
|
||||
<<value::binary-size(size_in_bytes), _padding::binary-size(padding_size_in_bytes),
|
||||
rest::binary()>> = data
|
||||
|
||||
{value, rest}
|
||||
end
|
||||
|
|
|
@ -98,8 +98,7 @@ defmodule ABI.TypeEncoder do
|
|||
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001"
|
||||
"""
|
||||
def encode(data, function_selector) do
|
||||
encode_method_id(function_selector) <>
|
||||
encode_raw(data, function_selector.types)
|
||||
encode_method_id(function_selector) <> encode_raw(data, function_selector.types)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -120,11 +119,13 @@ defmodule ABI.TypeEncoder do
|
|||
|
||||
@spec encode_method_id(%ABI.FunctionSelector{}) :: binary()
|
||||
defp encode_method_id(%ABI.FunctionSelector{function: nil}), do: ""
|
||||
|
||||
defp encode_method_id(function_selector) do
|
||||
# Encode selector e.g. "baz(uint32,bool)" and take keccak
|
||||
kec = function_selector
|
||||
|> ABI.FunctionSelector.encode()
|
||||
|> ExthCrypto.Hash.Keccak.kec()
|
||||
kec =
|
||||
function_selector
|
||||
|> ABI.FunctionSelector.encode()
|
||||
|> ExthCrypto.Hash.Keccak.kec()
|
||||
|
||||
# Take first four bytes
|
||||
<<init::binary-size(4), _rest::binary>> = kec
|
||||
|
@ -133,65 +134,74 @@ defmodule ABI.TypeEncoder do
|
|||
init
|
||||
end
|
||||
|
||||
@spec do_encode([ABI.FunctionSelector.type], [any()], [binary()]) :: binary()
|
||||
@spec do_encode([ABI.FunctionSelector.type()], [any()], [binary()]) :: binary()
|
||||
defp do_encode([], _, acc), do: :erlang.iolist_to_binary(Enum.reverse(acc))
|
||||
defp do_encode([type|remaining_types], data, acc) do
|
||||
|
||||
defp do_encode([type | remaining_types], data, acc) do
|
||||
{encoded, remaining_data} = encode_type(type, data)
|
||||
|
||||
do_encode(remaining_types, remaining_data, [encoded | acc])
|
||||
end
|
||||
|
||||
@spec encode_type(ABI.FunctionSelector.type, [any()]) :: {binary(), [any()]}
|
||||
defp encode_type({:uint, size}, [data|rest]) do
|
||||
@spec encode_type(ABI.FunctionSelector.type(), [any()]) :: {binary(), [any()]}
|
||||
defp encode_type({:uint, size}, [data | rest]) do
|
||||
{encode_uint(data, size), rest}
|
||||
end
|
||||
|
||||
defp encode_type(:address, data), do: encode_type({:uint, 160}, data)
|
||||
|
||||
defp encode_type(:bool, [data|rest]) do
|
||||
value = case data do
|
||||
true -> encode_uint(1, 8)
|
||||
false -> encode_uint(0, 8)
|
||||
_ -> raise "Invalid data for bool: #{data}"
|
||||
end
|
||||
defp encode_type(:bool, [data | rest]) do
|
||||
value =
|
||||
case data do
|
||||
true -> encode_uint(1, 8)
|
||||
false -> encode_uint(0, 8)
|
||||
_ -> raise "Invalid data for bool: #{data}"
|
||||
end
|
||||
|
||||
{value, rest}
|
||||
end
|
||||
|
||||
defp encode_type(:string, [data|rest]) do
|
||||
defp encode_type(:string, [data | rest]) do
|
||||
{encode_uint(byte_size(data), 256) <> encode_bytes(data), rest}
|
||||
end
|
||||
|
||||
defp encode_type(:bytes, [data|rest]) do
|
||||
defp encode_type(:bytes, [data | rest]) do
|
||||
{encode_uint(byte_size(data), 256) <> encode_bytes(data), rest}
|
||||
end
|
||||
|
||||
defp encode_type({:bytes, size}, [data|rest]) when is_binary(data) and byte_size(data) <= size do
|
||||
defp encode_type({:bytes, size}, [data | rest])
|
||||
when is_binary(data) and byte_size(data) <= size do
|
||||
{encode_bytes(data), rest}
|
||||
end
|
||||
defp encode_type({:bytes, size}, [data|_]) when is_binary(data) do
|
||||
|
||||
defp encode_type({:bytes, size}, [data | _]) when is_binary(data) do
|
||||
raise "size mismatch for bytes#{size}: #{inspect(data)}"
|
||||
end
|
||||
defp encode_type({:bytes, size}, [data|_]) do
|
||||
|
||||
defp encode_type({:bytes, size}, [data | _]) do
|
||||
raise "wrong datatype for bytes#{size}: #{inspect(data)}"
|
||||
end
|
||||
|
||||
defp encode_type({:tuple, types}, [data|rest]) do
|
||||
defp encode_type({:tuple, types}, [data | rest]) do
|
||||
# all head items are 32 bytes in length and there will be exactly
|
||||
# `count(types)` of them, so the tail starts at `32 * count(types)`.
|
||||
tail_start = ( types |> Enum.count ) * 32
|
||||
tail_start = (types |> Enum.count()) * 32
|
||||
|
||||
{head, tail, [], _} = Enum.reduce(types, {<<>>, <<>>, data |> Tuple.to_list, tail_start}, fn type, {head, tail, data, tail_position} ->
|
||||
{el, rest} = encode_type(type, data)
|
||||
{head, tail, [], _} =
|
||||
Enum.reduce(types, {<<>>, <<>>, data |> Tuple.to_list(), tail_start}, fn type,
|
||||
{head, tail, data,
|
||||
tail_position} ->
|
||||
{el, rest} = encode_type(type, data)
|
||||
|
||||
if ABI.FunctionSelector.is_dynamic?(type) do
|
||||
# If we're a dynamic type, just encoded the length to head and the element to body
|
||||
{head <> encode_uint(tail_position, 256), tail <> el, rest, tail_position + byte_size(el)}
|
||||
else
|
||||
# If we're a static type, simply encode the el to the head
|
||||
{head <> el, tail, rest, tail_position}
|
||||
end
|
||||
end)
|
||||
if ABI.FunctionSelector.is_dynamic?(type) do
|
||||
# If we're a dynamic type, just encoded the length to head and the element to body
|
||||
{head <> encode_uint(tail_position, 256), tail <> el, rest,
|
||||
tail_position + byte_size(el)}
|
||||
else
|
||||
# If we're a static type, simply encode the el to the head
|
||||
{head <> el, tail, rest, tail_position}
|
||||
end
|
||||
end)
|
||||
|
||||
{head <> tail, rest}
|
||||
end
|
||||
|
@ -199,10 +209,10 @@ defmodule ABI.TypeEncoder do
|
|||
defp encode_type({:array, type, element_count}, [data | rest]) do
|
||||
repeated_type = Enum.map(1..element_count, fn _ -> type end)
|
||||
|
||||
encode_type({:tuple, repeated_type}, [data |> List.to_tuple | rest])
|
||||
encode_type({:tuple, repeated_type}, [data |> List.to_tuple() | rest])
|
||||
end
|
||||
|
||||
defp encode_type({:array, type}, [data|_rest]=all_data) do
|
||||
defp encode_type({:array, type}, [data | _rest] = all_data) do
|
||||
element_count = Enum.count(data)
|
||||
|
||||
encoded_uint = encode_uint(element_count, 256)
|
||||
|
@ -212,7 +222,7 @@ defmodule ABI.TypeEncoder do
|
|||
end
|
||||
|
||||
defp encode_type(els, _) do
|
||||
raise "Unsupported encoding type: #{inspect els}"
|
||||
raise "Unsupported encoding type: #{inspect(els)}"
|
||||
end
|
||||
|
||||
def encode_bytes(bytes) do
|
||||
|
@ -222,10 +232,14 @@ defmodule ABI.TypeEncoder do
|
|||
# Note, we'll accept a binary or an integer here, so long as the
|
||||
# binary is not longer than our allowed data size
|
||||
defp encode_uint(data, size_in_bits) when rem(size_in_bits, 8) == 0 do
|
||||
size_in_bytes = ( size_in_bits / 8 ) |> round
|
||||
size_in_bytes = (size_in_bits / 8) |> round
|
||||
bin = maybe_encode_unsigned(data)
|
||||
|
||||
if byte_size(bin) > size_in_bytes, do: raise "Data overflow encoding uint, data `#{data}` cannot fit in #{size_in_bytes * 8} bits"
|
||||
if byte_size(bin) > size_in_bytes,
|
||||
do:
|
||||
raise(
|
||||
"Data overflow encoding uint, data `#{data}` cannot fit in #{size_in_bytes * 8} bits"
|
||||
)
|
||||
|
||||
bin |> pad(size_in_bytes, :left)
|
||||
end
|
||||
|
@ -233,7 +247,7 @@ defmodule ABI.TypeEncoder do
|
|||
defp pad(bin, size_in_bytes, direction) do
|
||||
# TODO: Create `left_pad` repo, err, add to `ExthCrypto.Math`
|
||||
total_size = size_in_bytes + ExthCrypto.Math.mod(32 - size_in_bytes, 32)
|
||||
padding_size_bits = ( total_size - byte_size(bin) ) * 8
|
||||
padding_size_bits = (total_size - byte_size(bin)) * 8
|
||||
padding = <<0::size(padding_size_bits)>>
|
||||
|
||||
case direction do
|
||||
|
@ -245,5 +259,4 @@ defmodule ABI.TypeEncoder do
|
|||
@spec maybe_encode_unsigned(binary() | integer()) :: binary()
|
||||
defp maybe_encode_unsigned(bin) when is_binary(bin), do: bin
|
||||
defp maybe_encode_unsigned(int) when is_integer(int), do: :binary.encode_unsigned(int)
|
||||
|
||||
end
|
||||
|
|
10
mix.exs
10
mix.exs
|
@ -2,14 +2,14 @@ defmodule ABI.Mixfile do
|
|||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[app: :abi,
|
||||
[app: :ex_abi,
|
||||
version: "0.1.12",
|
||||
elixir: "~> 1.4",
|
||||
elixir: "~> 1.6",
|
||||
description: "Ethereum's ABI Interface",
|
||||
package: [
|
||||
maintainers: ["Geoffrey Hayes", "Mason Fischer"],
|
||||
licenses: ["MIT"],
|
||||
links: %{"GitHub" => "https://github.com/exthereum/abi"}
|
||||
maintainers: ["Ayrat Badykov"],
|
||||
licenses: ["GPL-3.0"],
|
||||
links: %{"GitHub" => "https://github.com/poanetwork/ex_abi"}
|
||||
],
|
||||
build_embedded: Mix.env == :prod,
|
||||
start_permanent: Mix.env == :prod,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
defmodule ABI.FunctionSelectorTest do
|
||||
use ExUnit.Case, async: true
|
||||
doctest ABI.FunctionSelector
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
defmodule ABI.TypeDecoderTest do
|
||||
use ExUnit.Case, async: true
|
||||
doctest ABI.TypeDecoder
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
defmodule ABI.TypeEncoderTest do
|
||||
use ExUnit.Case, async: true
|
||||
doctest ABI.TypeEncoder
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
defmodule ABITest do
|
||||
use ExUnit.Case
|
||||
doctest ABI
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue