parent
fd30125b1f
commit
b078ed7a76
@ -0,0 +1,92 @@ |
||||
defmodule Explorer.ExchangeRates.Source.CoinGecko do |
||||
@moduledoc """ |
||||
Adapter for fetching exchange rates from https://coingecko.com |
||||
""" |
||||
|
||||
alias Explorer.ExchangeRates.{Source, Token} |
||||
alias HTTPoison.{Error, Response} |
||||
|
||||
@behaviour Source |
||||
|
||||
@impl Source |
||||
def fetch_exchange_rates do |
||||
headers = [{"Content-Type", "application/json"}] |
||||
|
||||
case HTTPoison.get(source_url(), headers) do |
||||
{:ok, %Response{body: body, status_code: 200}} -> |
||||
{:ok, format_data(body)} |
||||
|
||||
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 -> |
||||
{:error, decode_json(body)["error"]} |
||||
|
||||
{:error, %Error{reason: reason}} -> |
||||
{:error, reason} |
||||
end |
||||
end |
||||
|
||||
@doc false |
||||
def format_data(data) do |
||||
{:ok, price} = get_btc_price() |
||||
btc_price = to_decimal(price) |
||||
|
||||
for item <- decode_json(data), |
||||
not is_nil(item["total_supply"]) and not is_nil(item["current_price"]) do |
||||
{:ok, last_updated, 0} = DateTime.from_iso8601(item["last_updated"]) |
||||
|
||||
current_price = to_decimal(item["current_price"]) |
||||
|
||||
id = item["id"] |
||||
btc_value = if id != "btc", do: Decimal.div(current_price, btc_price), else: 1 |
||||
|
||||
%Token{ |
||||
available_supply: to_decimal(item["total_supply"]), |
||||
btc_value: btc_value, |
||||
id: id, |
||||
last_updated: last_updated, |
||||
market_cap_usd: to_decimal(item["market_cap"]), |
||||
name: item["name"], |
||||
symbol: item["symbol"], |
||||
usd_value: current_price, |
||||
volume_24h_usd: to_decimal(item["total_volume"]) |
||||
} |
||||
end |
||||
end |
||||
|
||||
defp base_url do |
||||
configured_url = Application.get_env(:explorer, __MODULE__, [])[:base_url] |
||||
configured_url || "https://api.coingecko.com/api/v3" |
||||
end |
||||
|
||||
defp decode_json(data) do |
||||
Jason.decode!(data) |
||||
end |
||||
|
||||
defp to_decimal(nil), do: nil |
||||
|
||||
defp to_decimal(value) do |
||||
Decimal.new(value) |
||||
end |
||||
|
||||
defp source_url(currency \\ "usd") do |
||||
"#{base_url()}/coins/markets?vs_currency=#{currency}" |
||||
end |
||||
|
||||
defp get_btc_price(currency \\ "usd") do |
||||
headers = [{"Content-Type", "application/json"}] |
||||
url = "#{base_url()}/exchange_rates" |
||||
|
||||
case HTTPoison.get(url, headers) do |
||||
{:ok, %Response{body: body, status_code: 200}} -> |
||||
data = decode_json(body) |
||||
current_price = data["rates"][currency]["value"] |
||||
|
||||
{:ok, current_price} |
||||
|
||||
{:ok, %Response{body: body, status_code: status_code}} when status_code in 400..499 -> |
||||
{:error, decode_json(body)["error"]} |
||||
|
||||
{:error, %Error{reason: reason}} -> |
||||
{:error, reason} |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue