defmodule Insight do defmodule Utxo do defstruct [ :txid, :vout, :address, :script, :satoshis ] end defmodule Tx do defstruct [ :addresses, :block_height, :block_index, :confidence, :confirmations, :data_protocol, :double_spend, :fees, :hash, :inputs, :lock_time, :outputs, :preference, :received, :relayed_by, :size, :total, :ver, :vin_sz, :vout_sz ] end defmacro __using__(endpoint) when is_binary(endpoint) do quote do require Logger @endpoint unquote endpoint @spec get_balance(String.t) :: {:ok, float} | {:error, any} def get_balance(address) do request = HTTPoison.get("#{@endpoint}addr/#{address}/balance", [], params: %{noCache: 1}) case request do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> with {balance, _} <- Integer.parse(body) do {:ok, balance / 100_000_000} else _ -> error = "Could not convert #{inspect body} to integer" Logger.error("[Insight][UTXO] #{error}") {:error, error} end {:ok, %HTTPoison.Response{status_code: status, body: body}} -> Logger.error("[Insight][UTXO] HTTP error #{inspect %{status_code: status, body: body}}") {:error, {status, body}} {:error, %HTTPoison.Error{reason: reason}} -> Logger.error("[Insight][UTXO] HTTPoison error #{inspect %{reason: reason}}") {:error, reason} end end @spec get_utxos(String.t) :: {:ok, list(map)} | {:error, any} def get_utxos(address) do request = HTTPoison.get("#{@endpoint}addr/#{address}/utxo", [], params: %{noCache: 1}) case request do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> txrefs = Poison.decode! body utxos = Enum.map txrefs, fn tx -> %Utxo{ txid: tx["txid"], vout: tx["vout"], address: address, script: tx["scriptPubKey"], satoshis: round(tx["amount"] * 100000000) } end Logger.info "[Insight][UTXO] OK #{inspect Enum.count utxos}" {:ok, utxos} {:ok, %HTTPoison.Response{status_code: status, body: body}} -> Logger.error "[Insight][UTXO] HTTP error #{inspect %{status_code: status, body: body}}" {:error, {status, body}} {:error, %HTTPoison.Error{reason: reason}} -> Logger.error "[Insight][UTXO] HTTPoison error #{inspect %{reason: reason}}" {:error, reason} end end @spec broadcast(binary) :: {:ok, map} | {:error, any} def broadcast(signed) do request = HTTPoison.post("#{@endpoint}tx/send", {:form, [rawtx: signed]}) case request do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> tx = %Tx{hash: (Poison.decode!(body))["txid"]} Logger.info "[Insight][TX] OK #{inspect tx}" {:ok, tx} {:ok, %HTTPoison.Response{status_code: status, body: body}} -> Logger.error "[Insight][TX] HTTP error #{inspect %{status_code: status, body: body}}" {:error, {status, body}} {:error, %HTTPoison.Error{reason: reason}} -> Logger.error "[Insight][TX] HTTPoison error #{inspect %{reason: reason}}" {:error, reason} end end defp map_atomize(map) do Map.new Enum.map map, fn {key, val} -> {String.to_atom(key), val} end end end end defmacro __using__(args) when is_list(args) do quote do Insight.__using__ "https://insight.bitpay.com/api/" end end end