From b078ed7a76374a4dcc819d88eafa144d94b93096 Mon Sep 17 00:00:00 2001 From: Lokraan Date: Mon, 22 Oct 2018 23:28:20 -0500 Subject: [PATCH] Create module to interact with coingecko api. --- .../exchange_rates/source/coin_gecko.ex | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex diff --git a/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex new file mode 100644 index 0000000000..cf6e2d90a9 --- /dev/null +++ b/apps/explorer/lib/explorer/exchange_rates/source/coin_gecko.ex @@ -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