defmodule EthValidation do
import ExKeccak
def valid_address?("0x" <> address = full_address) when byte_size(address) == 40 do
case to_checksum_address(full_address) do
{:ok, checksum} -> checksum == full_address
_ -> false
end
end
def valid_address?(_address), do: false
def to_checksum_address("0x" <> address) when byte_size(address) == 40 do
address = address |> String.downcase()
hash = address
|> hash_256()
|> Base.encode16(case: :lower)
checksum = Enum.zip(
String.graphemes(address),
String.graphemes(hash)
)
|> Enum.map_join(fn {each_address, each_hash} ->
cond do
String.match?(each_address, ~r/[0-9]/) -> each_address
String.match?(each_address, ~r/[a-f]/) and elem(Integer.parse(each_hash, 16), 0) >= 8 ->
String.upcase(each_address)
String.match?(each_address, ~r/[a-f]/) -> each_address
true -> raise "Error"
end
end)
{:ok, "0x" <> checksum}
end
def to_checksum_address(_address) do
{:error, "cannot convert to checksum address"}
end
end