Packages

Various modules and helpers for working with Nimiq primitives in the Gleam programming language or as a CLI

Current section

Files

Jump to
nimiq_gleam src address.erl
Raw

src/address.erl

-module(address).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([serialize/1, to_hex/1, to_base64/1, to_base64_url/1, unserialize/1, from_hex/1, from_base64/1, from_base64_url/1, from_user_friendly_address/1, from_string/1, to_user_friendly_address/1]).
-export_type([address/0]).
-opaque address() :: {address, bitstring()}.
-spec serialize(address()) -> bitstring().
serialize(Address) ->
erlang:element(2, Address).
-spec to_hex(address()) -> binary().
to_hex(Address) ->
_pipe = binary:encode_hex(erlang:element(2, Address)),
gleam@string:lowercase(_pipe).
-spec to_base64(address()) -> binary().
to_base64(Address) ->
gleam_stdlib:bit_array_base64_encode(erlang:element(2, Address), true).
-spec to_base64_url(address()) -> binary().
to_base64_url(Address) ->
gleam@bit_array:base64_url_encode(erlang:element(2, Address), true).
-spec iban_check(binary()) -> integer().
iban_check(Str) ->
Num = begin
_pipe = Str,
_pipe@1 = gleam@string:uppercase(_pipe),
_pipe@2 = gleam@string:to_utf_codepoints(_pipe@1),
_pipe@3 = gleam@list:zip(_pipe@2, gleam@string:split(Str, <<""/utf8>>)),
_pipe@4 = gleam@list:map(
_pipe@3,
fun(Tuple) ->
case gleam@string:utf_codepoint_to_int(erlang:element(1, Tuple)) of
Code when (Code >= 48) andalso (Code =< 57) ->
erlang:element(2, Tuple);
Code@1 ->
gleam@int:to_string(Code@1 - 55)
end
end
),
gleam@string:join(_pipe@4, <<""/utf8>>)
end,
Range = begin
_pipe@5 = Num,
_pipe@6 = gleam@string:length(_pipe@5),
_pipe@7 = gleam@int:to_float(_pipe@6),
_pipe@8 = gleam@float:divide(_pipe@7, 6.0),
_pipe@9 = gleam@result:unwrap(_pipe@8, +0.0),
_pipe@10 = gleam@float:ceiling(_pipe@9),
_pipe@11 = gleam@float:round(_pipe@10),
_pipe@12 = gleam@int:subtract(_pipe@11, 1),
gleam@list:range(0, _pipe@12)
end,
Tmp@1 = begin
_pipe@13 = Range,
gleam@list:fold(
_pipe@13,
<<""/utf8>>,
fun(Tmp, I) ->
_pipe@14 = (<<Tmp/binary,
(gleam@string:slice(Num, I * 6, 6))/binary>>),
_pipe@15 = gleam@int:parse(_pipe@14),
_pipe@16 = gleam@result:unwrap(_pipe@15, 0),
_pipe@17 = gleam@int:modulo(_pipe@16, 97),
_pipe@18 = gleam@result:unwrap(_pipe@17, 0),
gleam@int:to_string(_pipe@18)
end
)
end,
_pipe@19 = gleam@int:parse(Tmp@1),
gleam@result:unwrap(_pipe@19, 0).
-spec unserialize(bitstring()) -> {ok, address()} | {error, binary()}.
unserialize(Buf) ->
case erlang:byte_size(Buf) =:= 20 of
false ->
{error, <<"Invalid address: wrong length"/utf8>>};
true ->
{ok, {address, Buf}}
end.
-spec from_hex(binary()) -> {ok, address()} | {error, binary()}.
from_hex(Hex) ->
case gleam_stdlib:base16_decode(Hex) of
{ok, Buf} ->
unserialize(Buf);
{error, _} ->
{error, <<"Invalid address: not a valid hex encoding"/utf8>>}
end.
-spec from_base64(binary()) -> {ok, address()} | {error, binary()}.
from_base64(Base64) ->
case gleam@bit_array:base64_decode(Base64) of
{ok, Buf} ->
unserialize(Buf);
{error, _} ->
{error, <<"Invalid address: not a valid base64 encoding"/utf8>>}
end.
-spec from_base64_url(binary()) -> {ok, address()} | {error, binary()}.
from_base64_url(Base64_url) ->
case gleam@bit_array:base64_url_decode(Base64_url) of
{ok, Buf} ->
unserialize(Buf);
{error, _} ->
{error, <<"Invalid address: not a valid base64 url encoding"/utf8>>}
end.
-spec from_user_friendly_address(binary()) -> {ok, address()} |
{error, binary()}.
from_user_friendly_address(Str) ->
Normalized = begin
_pipe = Str,
_pipe@1 = gleam@string:replace(_pipe, <<" "/utf8>>, <<""/utf8>>),
gleam@string:uppercase(_pipe@1)
end,
gleam@result:'try'(
case gleam@string:slice(Normalized, 0, 2) =:= <<"NQ"/utf8>> of
false ->
{error, <<"Invalid address: wrong country code"/utf8>>};
true ->
{ok, nil}
end,
fun(_) ->
gleam@result:'try'(case gleam@string:length(Normalized) =:= 36 of
false ->
{error, <<"Invalid address: wrong length"/utf8>>};
true ->
{ok, nil}
end, fun(_) ->
Encoded = gleam@string:drop_left(Normalized, 4),
gleam@result:'try'(
case iban_check(
<<Encoded/binary,
(gleam@string:slice(Normalized, 0, 4))/binary>>
)
=:= 1 of
false ->
{error,
<<"Invalid address: wrong checksum"/utf8>>};
true ->
{ok, nil}
end,
fun(_) ->
case base32:decode(
Encoded,
<<"0123456789ABCDEFGHJKLMNPQRSTUVXY"/utf8>>
) of
{ok, Buf} ->
unserialize(Buf);
{error, _} ->
{error,
<<"Invalid address: not a valid user friendly encoding"/utf8>>}
end
end
)
end)
end
).
-spec from_string(binary()) -> {ok, address()} | {error, binary()}.
from_string(Str) ->
_pipe = from_user_friendly_address(Str),
_pipe@1 = gleam@result:lazy_or(_pipe, fun() -> from_hex(Str) end),
_pipe@2 = gleam@result:lazy_or(_pipe@1, fun() -> from_base64(Str) end),
_pipe@3 = gleam@result:lazy_or(_pipe@2, fun() -> from_base64_url(Str) end),
gleam@result:map_error(
_pipe@3,
fun(_) -> <<"Invalid address: unknown format"/utf8>> end
).
-spec to_user_friendly_address(address()) -> binary().
to_user_friendly_address(Address) ->
Encoded = base32:encode(
erlang:element(2, Address),
<<"0123456789ABCDEFGHJKLMNPQRSTUVXY"/utf8>>
),
Check = begin
_pipe = (<<"00"/utf8,
(gleam@int:to_string(
98 - iban_check(
<<<<Encoded/binary, "NQ"/utf8>>/binary, "00"/utf8>>
)
))/binary>>),
gleam@string:slice(_pipe, -2, 2)
end,
Address@1 = <<<<"NQ"/utf8, Check/binary>>/binary, Encoded/binary>>,
_pipe@1 = gleam@list:range(0, 8),
_pipe@2 = gleam@list:map(
_pipe@1,
fun(I) -> gleam@string:slice(Address@1, I * 4, 4) end
),
gleam@string:join(_pipe@2, <<" "/utf8>>).