Manic (Manic v0.1.0) View Source

Manic is an Elixir client for interfacing with Bitcoin miner APIs.

Hex.pm GitHub GitHub Workflow Status

Manic is an Elixir client for interfacing with Bitcoin miner APIs.

Manic is a port of unwriter's Minercraft library for JavaScript, with some added Elixir goodies. Like Minercraft, Manic supports the beta version of the Merchant API, and its name is a nod to another classic computer game.

Features

Manic supports the following features:

  • Get dynamic fee rates from miners
  • Calculate the fee for any transaction
  • Push transactions directly to miners
  • Get the status of any transaction from miners
  • Automatically verifies the JSON Envelope signatures
Implemented specBRFC
Merchant API Specificationce852c4c2cd1
Fee Specificationfb567267440a
JSON Envelope Specification298e080a4598

Installation

The package can be installed by adding manic to your list of dependencies in mix.exs.

def deps do
  [
    {:manic, "~> 0.1.0"}
  ]
end

Usage

1. Initalize a miner client

Initialize a miner client with the full URL of the Merchant API endpoint.

iex> miner = Manic.miner "https://merchantapi.taal.com"
%Manic.Miner{}

A client can aslo be initialized using any of the keys from the list of known_miners/0. Additional headers can also be specified if necessary.

iex> miner = Manic.miner :mempool, headers: [{"token", token}]
%Manic.Miner{}

2. Get and calculate fees

The miner client can then be used to query the miner's up-to-date fee rates.

iex> Manic.Fees.get(miner)
{:ok, %{
  expires: ~U[2020-04-20 16:35:03.168Z],
  mine: %{data: 0.5, standard: 0.5},
  relay: %{data: 0.25, standard: 0.25},
  verified: true
}}

The fee for a transaction can be calculated using the given rates. Manic will accept hex encoded transaction or a BSV.Tx.t/0.

iex> Manic.Fees.calculate(rates.mine, tx)
{:ok, 346}

3. Push and query transactions

Manic can be used to push transactions directly to the miner. Hex encoded transactions or BSV.Tx.t/0 structs are accepted.

iex> Manic.TX.push(miner, tx)
{:ok, %{
  "api_version" => "0.1.0",
  "current_highest_block_hash" => "00000000000000000397a5a37c1f9b409b4b58e76fd6bcac06db1a3004cccb38",
  "current_highest_block_height" => 631603,
  "miner_id" => "03e92d3e5c3f7bd945dfbf48e7a99393b1bfb3f11f380ae30d286e7ff2aec5a270",
  "result_description" => "",
  "return_result" => "success",
  "timestamp" => "2020-04-21T14:04:39.563Z",
  "tx_second_mempool_expiry" => 0,
  "txid" => "9c8c5cf37f4ad1a82891ff647b13ec968f3ccb44af2d9deaa205b03ab70a81fa",
  "verified" => true
}}

Any transaction's status can be queried by its txid.

iex> Manic.TX.status(miner, "e4763d71925c2ac11a4de0b971164b099dbdb67221f03756fc79708d53b8800e")
{:ok, %{
  "api_version" => "0.1.0",
  "block_hash" => "000000000000000000983dee680071d63939f4690a8a797c022eddadc88f925e",
  "block_height" => 630712,
  "confirmations" => 765,
  "miner_id" => "03e92d3e5c3f7bd945dfbf48e7a99393b1bfb3f11f380ae30d286e7ff2aec5a270",
  "result_description" => "",
  "return_result" => "success",
  "timestamp" => "2020-04-20T21:45:38.808Z",
  "tx_second_mempool_expiry" => 0,
  "verified" => true
}}

Multi miners

In the examples above, each API function is invoked by passing a single miner client. Manic also provides a way of interacting with multiple miner clients concurrently, and yielding the response from any or all of the miners.

1. Initalize a multi-miner client

Initialize a multi miner client with a list of miner Merchant API endpoint details. The list can contain either a full URL, a key from the list of known_miners/0, or a tuple pair containing any additional options.

iex> Manic.multi([
...>   "https://merchantapi.taal.com",
...>   :matterpool,
...>   {:mempool, headers: [{"token", token}]}
...> ])
%Manic.Multi{}

2. Push a tx an any miner

By default, multi miner requests will yield until any of the miners responds. This is allows a transaction to be pushed to multiple miners concurrently, and return a response when the first response is recieved.

iex> Manic.multi(miners)
...> |> Manic.TX.push(tx)
{^miner, {:ok, %{
  "api_version" => "0.1.0",
  "current_highest_block_hash" => "00000000000000000397a5a37c1f9b409b4b58e76fd6bcac06db1a3004cccb38",
  "current_highest_block_height" => 631603,
  "miner_id" => "03e92d3e5c3f7bd945dfbf48e7a99393b1bfb3f11f380ae30d286e7ff2aec5a270",
  "result_description" => "",
  "return_result" => "success",
  "timestamp" => "2020-04-21T14:04:39.563Z",
  "tx_second_mempool_expiry" => 0,
  "txid" => "9c8c5cf37f4ad1a82891ff647b13ec968f3ccb44af2d9deaa205b03ab70a81fa",
  "verified" => true
}}}

3. Query all miners concurrently

Alternatively, a multi miner client can be initialized with the option yield: :all which awaits all miner clients to respond before returning the list of responses. This allows us to compare fees from multiple miners concurrently.

iex> Manic.multi(miners, yield: :all)
...> |> Manic.Fees.get
[
  {^miner, {:ok, %{
    expires: ~U[2020-04-20 16:35:03.168Z],
    mine: %{data: 0.5, standard: 0.5},
    relay: %{data: 0.25, standard: 0.25},
    verified: true
  }}},
  {^miner, {:ok, %{
    expires: ~U[2020-04-20 16:35:03.168Z],
    mine: %{data: 0.5, standard: 0.5},
    relay: %{data: 0.25, standard: 0.25},
    verified: true
  }}},
  {^miner, {:ok, %{
    expires: ~U[2020-04-20 16:35:03.168Z],
    mine: %{data: 0.5, standard: 0.5},
    relay: %{data: 0.25, standard: 0.25},
    verified: true
  }}}
]

Link to this section Summary

Types

Bitcoin miner API client

Bitcoin multi miner API client

Functions

Returns a map of Manic's known miners.

Returns a miner client for the given URL.

Returns a multi miner client for the given list of Merchant API endpoints.

Link to this section Types

Specs

miner() :: Manic.Miner.t()

Bitcoin miner API client

Specs

multi_miner() :: Manic.Multi.t()

Bitcoin multi miner API client

Link to this section Functions

Specs

known_miners() :: map()

Returns a map of Manic's known miners.

Where a miner is known, a miner client can be initialized with miner/2 passing the atom key of the known miner as the first argument.

Example

iex> Manic.known_miners
%{
  matterpool: "https://merchantapi.matterpool.io",
  mempool: "https://www.ddpurse.com/openapi",
  taal: "https://merchantapi.taal.com"
}
Link to this function

miner(url, options \\ [])

View Source

Specs

miner(String.t() | atom(), keyword()) :: miner()

Returns a miner client for the given URL.

The url argument can either be a full URL for the miner's Merchant API endpoint, or an atom key from the result of known_miners/0.

Options

The accepted options are:

  • :headers - Pass a list of additional headers in tuple pairs.

Examples

A miner client can be instantiated with a full URL.

iex> Manic.miner "https://merchantapi.taal.com"
%Manic.Miner{}

Instantiating a known miner with additional headers.

iex> Manic.miner :mempool, headers: [{"token", auth_token}]
%Manic.Miner{}
Link to this function

multi(urls, options \\ [])

View Source

Specs

multi(list(), keyword()) :: multi_miner()

Returns a multi miner client for the given list of Merchant API endpoints.

Each element of the give list can contain the same credentials given to miner/2.

Options

The accepted options are:

  • :yield - Set to :all to await and return all responses. Defaults to :any which awaits and returns the first response.
  • :timeout - Set a timeout for the reqeusts. Defaults to 5000. Set to :infinity to disable timeout.

Examples

A multi miner client can be instantiated with a list containing either a full URL, a key from the list of known_miners/0, or a tuple pair containing any additional options.

iex> Manic.multi([
...>   "https://merchantapi.taal.com",
...>   :matterpool,
...>   {:mempool, headers: [{"token", token}]}
...> ])
%Manic.Multi{}