Packages
kujira
0.1.49
0.1.80
0.1.79
0.1.78
0.1.77
0.1.76
0.1.75
0.1.74
0.1.73
0.1.72
0.1.71
0.1.70
0.1.69
0.1.68
0.1.67
0.1.66
0.1.65
0.1.64
0.1.63
0.1.62
0.1.61
0.1.60
0.1.59
0.1.58
0.1.57
0.1.56
0.1.55
0.1.54
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.48
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.42
0.1.41
0.1.40
0.1.39
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Elixir interfaces to Kujira dApps, for building indexers, APIs and bots
Current section
Files
Jump to
Current section
Files
lib/kujira/coin.ex
defmodule Kujira.Coin do
@moduledoc """
A Kujira.Token with an associated amount
"""
alias Kujira.Token
@regex ~r'([0-9]+)([a-zA-Z][a-zA-Z0-9/:._-]{2,127})'
# @regex_decimal_amount ~r/[[:digit:]]+(?:\.[[:digit:]]+)?|\.[[:digit:]]+/
defstruct [:token, :amount]
@type t :: %__MODULE__{token: Token.t(), amount: integer()}
@spec parse_coins(GRPC.Channel.t(), binary()) ::
{:ok, [__MODULE__.t()]}
| {:error, :invalid_denom}
| {:error, :invalid_integer_amount}
| {:error, GRPC.RPCError.t()}
@doc """
Parses an SDK coins string eg 100ukuji,200ibc/FFA3D0E9C3CDE729559FB71A09E9E6CFA5A85AFABAC9F3CB5DD3942BFF935F9C
"""
def parse_coins(channel, string) do
case string
|> String.split(",")
|> Task.async_stream(&parse_coin(channel, &1), timeout: :infinity)
|> Enum.reduce(
{:ok, []},
fn
{:ok, {:ok, coin}}, {:ok, acc} ->
{:ok, add_coin(coin, acc)}
{:ok, err}, _ ->
err
_, err ->
err
end
) do
{:ok, coins} -> {:ok, normalize(coins)}
err -> err
end
end
@doc """
Parses a single SDK coin string eg 100ukuji
"""
@spec parse_coin(GRPC.Channel.t(), binary()) ::
{:ok, __MODULE__.t()}
| {:error, :invalid_denom}
| {:error, :invalid_integer_amount}
| {:error, GRPC.RPCError.t()}
def parse_coin(channel, string) do
with [[_, amount, denom]] <- Regex.scan(@regex, string),
{amount, ""} <- Integer.parse(amount),
{:ok, token} <- Token.from_denom(channel, denom) do
{:ok, %__MODULE__{amount: amount, token: token}}
else
[] ->
{:error, :invalid_denom}
{_, _} ->
{:error, :invalid_integer_amount}
err ->
err
end
end
@doc """
Adds a single Coin to a list of Coins, increasing the `amount` value if already present
"""
@spec add_coin(__MODULE__.t(), [__MODULE__.t()]) :: [__MODULE__.t()]
def add_coin(coin, coins) do
case Enum.split_with(coins, &(&1.token.denom == coin.token.denom)) do
{[existing], rest} ->
[%{existing | amount: existing.amount + coin.amount} | rest]
{[], all} ->
[coin | all]
end
end
@doc """
Sorts the coins alphabetically by denom string
"""
@spec normalize([__MODULE__.t()]) :: [__MODULE__.t()]
def normalize(coins) do
Enum.sort_by(coins, & &1.token.denom)
end
@doc """
Creates a Decimal with the human value of the `amount`
"""
@spec to_decimal(Kujira.Coin.t()) :: Decimal.t()
def to_decimal(%__MODULE__{amount: amount, token: %{meta: %Token.Meta{decimals: decimals}}}) do
%Decimal{sign: 1, coef: amount, exp: -decimals}
|> Decimal.normalize()
end
end