Packages
kujira
0.1.56
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/token/meta.ex
defmodule Kujira.Token.Meta do
defmodule Error do
defstruct [:error]
@type t :: %__MODULE__{
error:
:denom_unit_not_found
| :chain_registry_entry_not_found
# If the token is an IBC token with multiple hops, we don't try and trace it back
| :indirect
}
def new(error), do: %__MODULE__{error: error}
end
@moduledoc """
Metadata for a token
"""
use Memoize
import Ibc.Core.Channel.V1.Query.Stub
alias Kujira.Ghost
alias Ibc.Core.Channel.V1.QueryChannelClientStateRequest
alias Ibc.Lightclients.Tendermint.V1.ClientState
alias Kujira.Token
@custom [Ghost]
defstruct [:name, :decimals, :symbol, :coingecko_id, :png, :svg]
@type t ::
%__MODULE__{
name: String.t(),
decimals: non_neg_integer(),
symbol: String.t(),
coingecko_id: String.t() | nil,
png: String.t() | nil,
svg: String.t() | nil
}
| __MODULE__.Error.t()
# Local token, fetch from kujira assetlist
@spec from_token(GRPC.Channel.t(), Kujira.Token.t()) :: {:ok, Kujira.Token.Meta.t()}
def from_token(channel, %Token{denom: denom, trace: nil}) do
case Enum.reduce(@custom, nil, fn v, _ ->
v.token_meta(channel, %Token{denom: denom, trace: nil})
end) do
nil ->
with {:ok, res} <- ChainRegistry.chain_assets("kujira") do
res
|> Map.get("assets", [])
|> Enum.find(&(&1["base"] == denom))
|> from_chain_registry()
end
%__MODULE__{} = meta ->
{:ok, meta}
end
end
# Local token, fetch from kujira assetlist
def from_token(channel, %Token{
denom: _,
trace: %{path: "transfer/" <> trace, base_denom: denom}
}) do
[channel_id | _] = String.split(trace, "/")
with {:ok, chain_id} = get_counterparty_chain_id(channel, channel_id),
{:ok, chain_name} <- CosmosDirectory.chain_name(chain_id),
{:ok, res} <- ChainRegistry.chain_assets(chain_name) do
res
|> Map.get("assets")
|> Enum.find(&(&1["base"] == denom))
|> from_chain_registry()
end
end
defp from_chain_registry(
%{
"name" => name,
"symbol" => symbol,
"denom_units" => denom_units,
"display" => display
} = item
) do
with %{"exponent" => decimals} <-
Enum.find(denom_units, &(&1["denom"] == display)) do
{:ok,
%__MODULE__{
name: name,
decimals: decimals,
symbol: symbol,
coingecko_id: Map.get(item, "coingecko_id", nil),
png: item |> Map.get("images", []) |> Enum.at(0, %{}) |> Map.get("png", nil),
svg: item |> Map.get("images", []) |> Enum.at(0, %{}) |> Map.get("svg", nil)
}}
else
nil ->
{:ok, __MODULE__.Error.new(:denom_unit_not_found)}
end
end
defp from_chain_registry(nil) do
{:ok, __MODULE__.Error.new(:chain_registry_entry_not_found)}
end
defp get_counterparty_chain_id(channel, channel_id) do
Memoize.Cache.get_or_run(
{__MODULE__, :get_counterparty_chain_id, [channel_id]},
fn ->
with {:ok, %{identified_client_state: %{client_state: client_state}}} <-
channel_client_state(
channel,
QueryChannelClientStateRequest.new(port_id: "transfer", channel_id: channel_id)
),
%ClientState{chain_id: chain_id} <- Kujira.decode_any(client_state) do
{:ok, chain_id}
end
end
)
end
end