Minercraft
Interact with Bitcoin miner APIs
Minercraft is a JavaScript library for effortlessly interacting with Bitcoin Miner APIs. Currently supporting the beta version of the Merchant API.
Minercraft works both on the server as well as inside a browser.
What it does
Miner merchant APIs must follow the BRFC spec at https://github.com/bitcoin-sv/merchantapi-reference
- Get fee rates from a miner
- Calculate fee from a raw transaction
- Query the status of a single transaction
- Push a transaction to a miner
Miners
The bitcoin miners currently providing the merchant API beta endpoints are:
install
1. In browser
<script src='https://unpkg.com/minercraft'></script>
Check out an in-browser demo here: Minercraft Browser Demo (Source code here)
2. In node.js
npm install --save minercraft
API
0. Create a miner unit
Initialize with a miner API (must follow the miner merchant API spec: https://github.com/bitcoin-sv-specs/brfc-merchantapi)
Example:
const miner = new Minercraft({
url: "https://www.ddpurse.com/openapi",
headers: {
token: "561b756d12572020ea9a104c3441b71790acbbce95a6ddbf7e0630971af9424b"
}
})
a. TAAL.com
You can use the following config to connect to TAAL merchant API (Tentative):
const miner = new Minercraft({
"url": "https://merchantapi.taal.com"
})
b. Mempool.com
You can use the following config to connect to Mempool.com merchant API (Tentative) using the beta token (free):
const miner = new Minercraft({
url: "https://www.ddpurse.com/openapi",
headers: {
token: "561b756d12572020ea9a104c3441b71790acbbce95a6ddbf7e0630971af9424b"
}
})
c. Matterpool.io
You can use the following config to connect to Matterpool.io merchant API:
const miner = new Minercraft({
url: "https://merchantapi.matterpool.io"
})
1. Get the fee rate
Query a miner's fee rate:
let rate = await miner.fee.rate()
console.log("fee rate:", rate)
will print:
fee rate: {
"valid": true,
"expires": "2020-04-30T13:05:16.925Z",
"mine": { "standard": 0.5, "data": 0.5 },
"relay": { "standard": 0.25, "data": 0.25 }
}
You can also pass in an additional parameter verbose: true
to get the raw response from the API, which includes other metadata such as minerID and signature, which you can use to verify authenticity:
let rate = await miner.fee.rate({ verbose: true })
console.log("verbose fee rate:", rate)
2. Calculate fee for a transaction
Calculate total fee, based on a fixed rate:
let fee = miner.fee.get({
rate: { data: 0.5, standard: 0.5 },
tx: "0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000"
})
First query the fee rate from a miner, and then use it to calcluate the total fee for a transaction:
let rate = await miner.fee.rate()
let fee = miner.fee.get({
rate: rate.mine,
tx: "0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000"
})
console.log("fee = ", fee)
will print:
fee = 348
3. Get transaction status
Query the miner to check what the status of a transaction is:
let status = miner.tx.status("e4763d71925c2ac11a4de0b971164b099dbdb67221f03756fc79708d53b8800e")
console.log(status)
will print:
{
"apiVersion": "0.1.0",
"timestamp": "2020-04-15T19:51:51.020Z",
"returnResult": "success",
"resultDescription": "",
"blockHash": "000000000000000004a5686ff15cdb3950939bdc5725970d963e2b03d3d43d45",
"blockHeight": 630700,
"confirmations": 50,
"minerId": "03c51d59a737a0ebc064344bf206b7140bf51a9ef8d6cb75dc2d726853d7c76758",
"txSecondMempoolExpiry": 0,
"valid": true
}
If you want to get a more detailed response, including the minerID and signature, you can call the method with {verbose: true}
:
let status = await miner.tx.status(txid, { verbose: true })
console.log(status)
will print something like:
{
"payload": {
"apiVersion": "0.1.0",
"timestamp": "2020-04-19T15:06:56.299Z",
"returnResult": "success",
"resultDescription": "",
"blockHash": "000000000000000004a5686ff15cdb3950939bdc5725970d963e2b03d3d43d45",
"blockHeight": 630700,
"confirmations": 603,
"minerId": "03e92d3e5c3f7bd945dfbf48e7a99393b1bfb3f11f380ae30d286e7ff2aec5a270",
"txSecondMempoolExpiry": 0
},
"signature": "3044022032eb418ea68a0825767fa6bf038cca200acbbbabeadd7f7e3b203594e3ef3ee60220224fc0657a5c7c8b3b4a8b71de897655a990b975ae9e9f8d574eb806663bc839",
"publicKey": "03e92d3e5c3f7bd945dfbf48e7a99393b1bfb3f11f380ae30d286e7ff2aec5a270",
"encoding": "UTF-8",
"mimetype": "application/json",
"valid": true
}
4. Push transaction
Pass a raw transaction hex string into the push()
function and it will send the transaction directly to the miner.
let response = await miner.tx.push("0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000")
Again, to get more verbose response, you can pass in { verbose: true }
:
let response = await miner.tx.push("0100000001648ed7d1c1a27ec923445c8d404e227145218c4ce01cf958a898c5a048e8f264020000006a47304402207dc1953455be091c8df18e7f7e1424bc4efdced3e400642f8316e3ef298c3f30022062d833b3f1b94593ec7c088b930e2987475c7d99bf19f5714b12a9facff100df41210273f105be3e7ca116e96c7c40f17267ae05ede7160eb099aa2146a88b6328f4ecffffffff030000000000000000fdc901006a223144535869386876786e36506434546176686d544b7855374255715337636e7868770c57544458565633505a4b474414e5ae89e5bebd2fe585ade5ae892fe99c8de982b119323032302d30342d30365430363a30303a30302b30383a30304c697b22617169223a223538222c22706d3235223a223332222c22706d3130223a223636222c22736f32223a2235222c226e6f32223a223235222c22636f223a22302e373530222c226f33223a223635222c22706f6c223a22504d3130222c22717561223a22e889af227d4cfb78da75d1c16a02311006e077c959964cb29944dfa1d07bf1209e0a6b57b137114aaf2d2d5e446d7b29d59e3c492f22f834d9ea5b3859e826bba4b73fc34cf898b999b0dee89675184ad662c3815094a5293370ca1a298f73415151ba2b9370cdfd9c124f34c55c563fe419c5eb2b9aa5b1fb1e3d7edf66c5cf93fdfa2ed6072a66ae2621d15203775d99fb070013c50da7cab45599c09b04062688999437993f53d91933ade6a7f5d16e37e7e5676842307553aa1b2685c19e02137a93a94c92c74c69dc54bc7f9c173bfbf21882745b379784a60e0a0f071ea4fce1a45f521a399cfae770f6f0605f67f6795f0381688010dd1da7dd0b690c97db22020000000000001976a914666675d887a7ae09835af934096d9fcbbb70eed288ac61290000000000001976a9149e7520bc258934a3d58704ab98ed0200e2c1bb9688ac00000000", {
verbose: true
})
This will provide more information about the response.
5. Validate API responses
Minercraft takes care of all the cryptographic validation of the API responses automatically.
Note that every response contains a "valid"
attribute which is either true
or false
.
It will be true if the signature matches the publickey and the content. Otherwise it will be false. This is the same for both the normal mode and the verbose mode. Here are some examples:
Normal Mode:
{
"valid": true,
"expires": "2020-04-30T13:05:16.525Z",
"mine": { "standard": 0.5, "data": 0.5 },
"relay": { "standard": 0.25, "data": 0.25 }
}
Verbose Mode:
{
"payload": {
"apiVersion": "0.1.0",
"timestamp": "2020-04-30T12:55:26.581Z",
"returnResult": "success",
"resultDescription": "",
"blockHash": "000000000000000004a5686ff15cdb3950939bdc5725970d963e2b03d3d43d45",
"blockHeight": 630700,
"confirmations": 2167,
"minerId": "03c51d59a737a0ebc064344bf206b7140bf51a9ef8d6cb75dc2d726853d7c76758",
"txSecondMempoolExpiry": 0
},
"signature": "304402206a15cc626cb8e959aeb53eb4224cdd7150c56ae662ed236d7042265f21cbc8f802200bf97202bc0c09aae1f3993d28d4175ae24dd53225321c64cb9492c81f2ede03",
"publicKey": "03c51d59a737a0ebc064344bf206b7140bf51a9ef8d6cb75dc2d726853d7c76758",
"encoding": "UTF-8",
"mimetype": "applicaton/json",
"valid": true
}