mirror of
https://github.com/janoside/btc-rpc-explorer.git
synced 2026-08-13 12:33:13 +02:00
API v2.0.0
- all actions return JSON - condense some actions - add /api/blockchain/next-halving https://github.com/janoside/btc-rpc-explorer/discussions/520
This commit is contained in:
parent
8950c95d56
commit
09a31f1e78
6 changed files with 247 additions and 231 deletions
|
|
@ -1,35 +1,51 @@
|
|||
This changelog specifically tracks changes to the Public API available at `/api` and is maintained separately from the app CHANGELOG such that it can properly adhere to semantic versioning.
|
||||
|
||||
##### v1.2.0
|
||||
##### v2.0.0
|
||||
###### Unreleased
|
||||
|
||||
* Added: /api/xyzpub/txids/:xyzpub
|
||||
* Added: /api/xyzpub/addresses/:xyzpub
|
||||
* Added: /api/block/header/:height
|
||||
* Added: /api/block/header/:hash
|
||||
* Added: /api/holidays/all
|
||||
* Added: /api/holidays/today
|
||||
* Added: /api/holidays/:day
|
||||
* Added: /api/tx/volume/24h
|
||||
* Changed: /api/tx/:txid
|
||||
* Added result.vin[i].scriptSig.address
|
||||
* Added result.vin[i].scriptSig.type
|
||||
* Added result.fee, including result.fee.amount and result.fee.unit
|
||||
* Added result.fun, when applicable, which includes special details about the tx
|
||||
* Changed path: /api/util/xyzpub/:xyzpub -> /api/xyzpub/:xyzpub (auto-redirect included)
|
||||
* Changed: /api/price[/...]
|
||||
* Return values exclude thousands separators by default; they can be added with "?format=true"
|
||||
* BREAKING: All actions now return JSON content
|
||||
* Added:
|
||||
* `/api/blocks/tip` (replaces `/api/blocks/tip/hash` and `/api/blocks/tip/height`)
|
||||
* `/api/xyzpub/txids/$XPUB`
|
||||
* `/api/xyzpub/addresses/$XPUB`
|
||||
* `/api/block/header/$HEIGHT`
|
||||
* `/api/block/header/$HASH`
|
||||
* `/api/blockchain/next-halving`
|
||||
* `/api/holidays/all`
|
||||
* `/api/holidays/today`
|
||||
* `/api/holidays/$DAY`
|
||||
* `/api/tx/volume/24h`
|
||||
* `/api/price/marketcap` (replaces `/api/price/$CURRENCY/marketcap`)
|
||||
* `/api/price/sats` (replaces `/api/price/$CURRENCY/sats`)
|
||||
* Changed output:
|
||||
* `/api/tx/$TXID`
|
||||
* Added result.vin[i].scriptSig.address
|
||||
* Added result.vin[i].scriptSig.type
|
||||
* Added result.fee, including result.fee.amount and result.fee.unit
|
||||
* Added result.fun, when applicable, which includes special details about the tx
|
||||
* `/api/price[/...]`
|
||||
* Return values exclude thousands separators by default; they can be added with "?format=true"
|
||||
* Changed path:
|
||||
* `/api/util/xyzpub/$XPUB` -> `/api/xyzpub/$XPUB` (auto-redirect included)
|
||||
* Removed:
|
||||
* `/api/blocks/tip/hash` (see `/api/blocks/tip`)
|
||||
* `/api/blocks/tip/height` (see `/api/blocks/tip`)
|
||||
* `/api/mempool/count` (see "size" field in output from `/api/mempool/summary`)
|
||||
* `/api/price/$CURRENCY/marketcap` (see individual fields in output from `/api/price/marketcap`)
|
||||
* `/api/price/$CURRENCY/sats` (see individual fields in output from `/api/price/sats`)
|
||||
|
||||
|
||||
|
||||
##### v1.1.0
|
||||
###### 2021-12-07
|
||||
|
||||
* Added: /api/blockchain/utxo-set
|
||||
* Added: /api/address/:address
|
||||
* Added: /api/mining/next-block
|
||||
* Added: /api/mining/next-block/txids
|
||||
* Added: /api/mining/next-block/includes/:txid
|
||||
* Added: /api/mining/miner-summary
|
||||
* Added:
|
||||
* `/api/blockchain/utxo-set`
|
||||
* `/api/address/$ADDRESS`
|
||||
* `/api/mining/next-block`
|
||||
* `/api/mining/next-block/txids`
|
||||
* `/api/mining/next-block/includes/$TXID`
|
||||
* `/api/mining/miner-summary`
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
##### v3.4.0
|
||||
###### Unreleased (beta)
|
||||
|
||||
* Breaking changes to the API (see [./api/changelog](/api/changlog))
|
||||
* Include median fee rate for next-block estimates, on homepage and at [/next-block](./next-block)
|
||||
* Minor fixes for running against Bitcoin Core v23
|
||||
* Block Analysis: include top "days destroyed" transactions
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const crypto = require('crypto');
|
|||
const url = require('url');
|
||||
const path = require('path');
|
||||
|
||||
const apiDocs = require("../docs/api.js");
|
||||
|
||||
let baseUrl = (process.env.BTCEXP_BASEURL || "/").trim();
|
||||
if (!baseUrl.startsWith("/")) {
|
||||
baseUrl = "/" + baseUrl;
|
||||
|
|
@ -90,6 +92,7 @@ module.exports = {
|
|||
secureSite: process.env.BTCEXP_SECURE_SITE == "true",
|
||||
|
||||
baseUrl: baseUrl,
|
||||
apiBaseUrl: apiDocs.baseUrl,
|
||||
|
||||
coin: currentCoin,
|
||||
|
||||
|
|
@ -252,7 +255,7 @@ module.exports = {
|
|||
|
||||
/* 14 */ {name:"Predicted Blocks", url:"./predicted-blocks", desc:"View predicted future blocks based on the current mempool.", iconClass:"bi-arrow-right-circle"},
|
||||
|
||||
/* 15 */ {name:"API", url:"./api/docs", desc:"View docs for the public API.", iconClass:"bi-braces-asterisk"},
|
||||
/* 15 */ {name:"API", url:`.${apiDocs.baseUrl}/docs`, desc:"View docs for the public API.", iconClass:"bi-braces-asterisk"},
|
||||
|
||||
/* 16 */ {name:"Next Block", url:"./next-block", desc:"View a prediction for the next block, based on the current mempool.", iconClass:"bi-minecart-loaded"},
|
||||
/* 17 */ {name:"Quotes", url:"./quotes", desc:"Curated list of Bitcoin-related quotes.", iconClass:"bi-chat-quote"},
|
||||
|
|
|
|||
184
docs/api.js
184
docs/api.js
|
|
@ -1,52 +1,41 @@
|
|||
module.exports = {
|
||||
"version": "1.2.0",
|
||||
"version": "2.0.0",
|
||||
"baseUrl": "/api",
|
||||
|
||||
"routes":[
|
||||
// blocks
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/block/:hash",
|
||||
"url":"/block/$HASH",
|
||||
"desc":"Returns the details of the block with the given hash.",
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/block/0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893"
|
||||
"testUrl":"/block/0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893"
|
||||
},
|
||||
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/block/:height",
|
||||
"url":"/block/$HEIGHT",
|
||||
"desc":"Returns the details of the block at the given height.",
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/block/123456"
|
||||
"testUrl":"/block/123456"
|
||||
},
|
||||
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/block/header/:hash",
|
||||
"url":"/block/header/$HASH",
|
||||
"desc":"Returns the details of the block header with the given hash.",
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/block/header/0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893"
|
||||
"testUrl":"/block/header/0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893"
|
||||
},
|
||||
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/block/header/:height",
|
||||
"url":"/block/header/$HEIGHT",
|
||||
"desc":"Returns the details of the block header at the given height.",
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/block/header/123456"
|
||||
"testUrl":"/block/header/123456"
|
||||
},
|
||||
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/blocks/tip/height",
|
||||
"desc":"Returns the height of the chain tip.",
|
||||
"returnType":"integer"
|
||||
},
|
||||
|
||||
{
|
||||
"category":"blocks",
|
||||
"url":"/api/blocks/tip/hash",
|
||||
"desc":"Returns the block hash of the chain tip.",
|
||||
"returnType":"string"
|
||||
"url":"/blocks/tip",
|
||||
"desc":"Returns basic details about the chain tip."
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -55,17 +44,15 @@ module.exports = {
|
|||
// transactions
|
||||
{
|
||||
"category":"transactions",
|
||||
"url":"/api/tx/:txid",
|
||||
"url":"/tx/$TXID",
|
||||
"desc":"Returns the details of the transaction with the given txid.",
|
||||
"returnType":"json",
|
||||
"testUrl": "/api/tx/f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
|
||||
"testUrl": "/tx/f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
|
||||
},
|
||||
{
|
||||
"category":"transactions",
|
||||
"url":"/api/tx/volume/24h",
|
||||
"url":"/tx/volume/24h",
|
||||
"desc":"Returns total output of all transactions over the last 24hrs.",
|
||||
"returnType":"json",
|
||||
"testUrl": "/api/tx/volume/24h",
|
||||
"testUrl": "/tx/volume/24h",
|
||||
"hideInSlowMode": true
|
||||
},
|
||||
|
||||
|
|
@ -75,15 +62,18 @@ module.exports = {
|
|||
// blockchain
|
||||
{
|
||||
"category":"blockchain",
|
||||
"url":"/api/blockchain/coins",
|
||||
"desc":"Returns the current supply of Bitcoin. An estimate using a checkpoint can be returned in 2 cases: on 'slow' devices, and before the UTXO Set snapshot is loaded.",
|
||||
"returnType":"number"
|
||||
"url":"/blockchain/coins",
|
||||
"desc":"Returns the current supply of Bitcoin. An estimate using a checkpoint can be returned in 2 cases: on 'slow' devices, and before the UTXO Set snapshot is loaded."
|
||||
},
|
||||
{
|
||||
"category":"blockchain",
|
||||
"url":"/api/blockchain/utxo-set",
|
||||
"desc":"Returns the latest UTXO Set snapshot. Warning: This call can be very slow, depending on node hardware and index configurations.",
|
||||
"returnType":"json"
|
||||
"url":"/blockchain/utxo-set",
|
||||
"desc":"Returns the latest UTXO Set snapshot. Warning: This call can be very slow, depending on node hardware and index configurations."
|
||||
},
|
||||
{
|
||||
"category":"blockchain",
|
||||
"url":"/blockchain/next-halving",
|
||||
"desc":"Returns details about the next, upcoming halving."
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -93,15 +83,14 @@ module.exports = {
|
|||
// addresses
|
||||
{
|
||||
"category":"addresses",
|
||||
"url":"/api/address/:address",
|
||||
"desc":"Returns a summary of data pertaining to the given address. The output of this call will depend heavily on the configured 'Address API' (see .env-sample file).",
|
||||
"url":"/address/$ADDRESS",
|
||||
"desc":"Returns a summary of data pertaining to the given address. The output of this call will depend heavily on the configured 'Address API' (see .env-sample file). If an Address API is configured, transactions related to the given address will be returned (the below optional parameters apply to those transactions).",
|
||||
"optionalParams": {
|
||||
"limit":"Number of transactions to return",
|
||||
"offset":"Offset into transactions",
|
||||
"sort":"Sorting direction for transactions ('desc'=new first, 'asc'=old first)"
|
||||
},
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/address/34rng4QwB5pHUbGDJw1JxjLwgEU8TQuEqv"
|
||||
"testUrl":"/address/34rng4QwB5pHUbGDJw1JxjLwgEU8TQuEqv"
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -111,37 +100,34 @@ module.exports = {
|
|||
// xyz-pubs
|
||||
{
|
||||
"category":"xpubs",
|
||||
"url":"/api/xyzpub/:extendedPubkey",
|
||||
"url":"/xyzpub/$XPUB",
|
||||
"desc":"Returns details for the specified extended public key, including related keys and addresses.",
|
||||
"returnType":"json",
|
||||
"optionalParams": {
|
||||
"limit":"The number of addresses to return",
|
||||
"offset":"Offset into the list of addresses"
|
||||
},
|
||||
"testUrl": "/api/util/xyzpub/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
"testUrl": "/util/xyzpub/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
},
|
||||
{
|
||||
"category":"xpubs",
|
||||
"url":"/api/xyzpub/addresses/:xyzpub",
|
||||
"url":"/xyzpub/addresses/$XPUB",
|
||||
"desc":"Returns a list of addresses derived from the given [xyz]pub.",
|
||||
"optionalParams": {
|
||||
"receiveOrChange":"0 for 'receive' addresses (default); 1 for 'change' addresses",
|
||||
"limit":"Number of addresses to return",
|
||||
"offset":"Offset into addresses"
|
||||
},
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/xyzpub/addresses/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
"testUrl":"/xyzpub/addresses/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
},
|
||||
{
|
||||
"category":"xpubs",
|
||||
"url":"/api/xyzpub/txids/:xyzpub",
|
||||
"url":"/xyzpub/txids/$XPUB",
|
||||
"desc":"Returns a list of transaction IDs associated with the given [xyz]pub.",
|
||||
"optionalParams": {
|
||||
"gapLimit":"Limit of empty addresses to end searching for transactions (default: 20)",
|
||||
"addressLimit":"Forced limit on the number of addresses to search through (both 'receive' and 'change' addresses up to this number will be searched)"
|
||||
},
|
||||
"returnType":"json",
|
||||
"testUrl":"/api/xyzpub/txids/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
"testUrl":"/xyzpub/txids/xpub6EuV33a2DXxAhoJTRTnr8qnysu81AA4YHpLY6o8NiGkEJ8KADJ35T64eJsStWsmRf1xXkEANVjXFXnaUKbRtFwuSPCLfDdZwYNZToh4LBCd"
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -150,45 +136,39 @@ module.exports = {
|
|||
// mining
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/hashrate",
|
||||
"desc":"Returns the network hash rate, estimated over the last 1, 7, 30, 90, and 365 days.",
|
||||
"returnType":"json"
|
||||
"url":"/mining/hashrate",
|
||||
"desc":"Returns the network hash rate, estimated over the last 1, 7, 30, 90, and 365 days."
|
||||
},
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/diff-adj-estimate",
|
||||
"desc":"Returns the current estimate for the next difficulty adjustment as a percentage.",
|
||||
"returnType":"number"
|
||||
"url":"/mining/diff-adj-estimate",
|
||||
"desc":"Returns the current estimate for the next difficulty adjustment as a percentage."
|
||||
},
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/next-block",
|
||||
"desc":"Returns a summary for the estimated next block to be mined (produced via getblocktemplate).",
|
||||
"returnType":"json"
|
||||
"url":"/mining/next-block",
|
||||
"desc":"Returns a summary for the estimated next block to be mined (produced via getblocktemplate)."
|
||||
},
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/next-block/txids",
|
||||
"desc":"Returns a list of the transaction IDs included in the estimated next block to be mined (produced via getblocktemplate).",
|
||||
"returnType":"json"
|
||||
"url":"/mining/next-block/txids",
|
||||
"desc":"Returns a list of the transaction IDs included in the estimated next block to be mined (produced via getblocktemplate)."
|
||||
},
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/next-block/includes/:txid",
|
||||
"url":"/mining/next-block/includes/$TXID",
|
||||
"desc":"Returns whether the specified transaction ID is included in the estimated next block to be mined (produced via getblocktemplate).",
|
||||
"returnType":"boolean",
|
||||
"testUrl":"/api/mining/next-block/includes/yourTxId"
|
||||
"testUrl":"/mining/next-block/includes/yourTxId"
|
||||
},
|
||||
{
|
||||
"category":"mining",
|
||||
"url":"/api/mining/miner-summary",
|
||||
"url":"/mining/miner-summary",
|
||||
"desc":"Returns whether the specified transaction ID is included in the estimated next block to be mined (produced via getblocktemplate).",
|
||||
"returnType":"json",
|
||||
"optionalParams": {
|
||||
"since":"Use the form 'Nd' to specify the number of day to look back (e.g. 'since=7d' will analyze the last 7 days)",
|
||||
"startHeight+endHeight":"Use these 2 parameters to specify a custom start/end height (e.g. 'startHeight=0&endHeight=24' to analyze the first 25 blocks)"
|
||||
},
|
||||
"testUrl":"/api/mining/miner-summary?since=1d"
|
||||
"testUrl":"/mining/miner-summary?since=1d"
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -198,22 +178,19 @@ module.exports = {
|
|||
// mempool
|
||||
{
|
||||
"category":"mempool",
|
||||
"url":"/api/mempool/count",
|
||||
"desc":"Returns the number of transactions in Bitcoin Core's mempool.",
|
||||
"returnType":"integer"
|
||||
"url":"/mempool/count",
|
||||
"desc":"Returns the number of transactions in Bitcoin Core's mempool."
|
||||
},
|
||||
{
|
||||
"category":"mempool",
|
||||
"url":"/api/mempool/summary",
|
||||
"url":"/mempool/summary",
|
||||
"desc":"Returns a summary of Bitcoin Core's mempool (full output from 'getmempoolinfo')",
|
||||
"returnType":"json",
|
||||
"example": {"loaded":true,"size":225,"bytes":76209,"usage":410496,"total_fee":0.01763495,"maxmempool":15000000,"mempoolminfee":0.00001,"minrelaytxfee":0.00001,"unbroadcastcount":0}
|
||||
},
|
||||
{
|
||||
"category":"mempool",
|
||||
"url":"/api/mempool/fees",
|
||||
"url":"/mempool/fees",
|
||||
"desc":"Returns recommended fee rates in sats/vB for next block, ~30 min, 1 hr, and 1 day.",
|
||||
"returnType":"json",
|
||||
"example": {"nextBlock":17,"30min":9,"60min":9,"1day":9}
|
||||
},
|
||||
|
||||
|
|
@ -222,39 +199,21 @@ module.exports = {
|
|||
// price
|
||||
{
|
||||
"category":"price",
|
||||
"url":"/api/price",
|
||||
"url":"/price",
|
||||
"desc":"Returns the price of 1 BTC, in USD, EUR, GBP, and XAU",
|
||||
"returnType":"json",
|
||||
"optionalParams": {
|
||||
"format":"Set to 'true' to include thousands-separator formatting in results"
|
||||
}
|
||||
},
|
||||
{
|
||||
"category":"price",
|
||||
"url":"/api/price/:currency",
|
||||
"desc":"Returns the price of 1 BTC, in one of USD, EUR, GBP, XAU",
|
||||
"params":[{name: "currency", "options": ["usd", "eur", "gbp", "xau"]}],
|
||||
"returnType":"number",
|
||||
"testUrl": "/api/price/usd",
|
||||
"optionalParams": {
|
||||
"format":"Set to 'true' to include thousands-separator formatting in results"
|
||||
}
|
||||
"url":"/price/marketcap",
|
||||
"desc":"Returns the market cap of Bitcoin, in USD, EUR, GBP, XAU",
|
||||
},
|
||||
{
|
||||
"category":"price",
|
||||
"url":"/api/price/:currency/marketcap",
|
||||
"desc":"Returns the market cap of Bitcoin, in one of USD, EUR, GBP, XAU",
|
||||
"params":[{name: "currency", "options": ["usd", "eur", "gbp", "xau"]}],
|
||||
"returnType":"number",
|
||||
"testUrl": "/api/price/usd/marketcap"
|
||||
},
|
||||
{
|
||||
"category":"price",
|
||||
"url":"/api/price/:currency/sats",
|
||||
"desc":"Returns the price of 1 unit of the specified currency (e.g. 1 \"usd\") in satoshis",
|
||||
"params":[{name: "currency", "options": ["usd", "eur", "gbp", "xau"]}],
|
||||
"returnType":"number",
|
||||
"testUrl": "/api/price/usd/sats"
|
||||
"url":"/price/sats",
|
||||
"desc":"Returns the price of 1 unit of [USD, EUR, GBP, XAU] (e.g. 1 \"usd\") in satoshis (aka \"Moscow Time\")",
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -263,45 +222,39 @@ module.exports = {
|
|||
// fun
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/quotes/all",
|
||||
"url":"/quotes/all",
|
||||
"desc":"Returns the full curated list of Bitcoin quotes.",
|
||||
"returnType":"json"
|
||||
},
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/quotes/:index",
|
||||
"url":"/quotes/$INDEX",
|
||||
"desc":"Returns the Bitcoin quote with the given index from the curated list.",
|
||||
"returnType":"json",
|
||||
"testUrl": "/api/quotes/0"
|
||||
"testUrl": "/quotes/0"
|
||||
},
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/quotes/random",
|
||||
"desc":"Returns a random Bitcoin quote from the curated list.",
|
||||
"returnType":"json"
|
||||
"url":"/quotes/random",
|
||||
"desc":"Returns a random Bitcoin quote from the curated list."
|
||||
},
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/holidays/all",
|
||||
"desc":"Returns the full curated list of Bitcoin Holidays.",
|
||||
"returnType":"json"
|
||||
"url":"/holidays/all",
|
||||
"desc":"Returns the full curated list of Bitcoin Holidays."
|
||||
},
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/holidays/today",
|
||||
"url":"/holidays/today",
|
||||
"desc":"Returns the Bitcoin Holidays celebrated 'today' (i.e. at the time the API call is made).",
|
||||
"optionalParams": {
|
||||
"tzOffset":"The number of hours to offset from UTC for the caller's local timezone, e.g. \"-5\" for EST"
|
||||
},
|
||||
"returnType":"json",
|
||||
"testUrl": "/api/holidays/today?tzOffset=-5"
|
||||
"testUrl": "/holidays/today?tzOffset=-5"
|
||||
},
|
||||
{
|
||||
"category":"fun",
|
||||
"url":"/api/holidays/:day",
|
||||
"url":"/holidays/$DAY",
|
||||
"desc":"Returns the Bitcoin Holidays celebrated on the specified day, using one of the following formats: yyyy-MM-DD, MM-DD.",
|
||||
"returnType":"json",
|
||||
"testUrl": "/api/holidays/01-03"
|
||||
"testUrl": "/holidays/01-03"
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -310,9 +263,8 @@ module.exports = {
|
|||
// admin
|
||||
{
|
||||
"category":"admin",
|
||||
"url":"/api/version",
|
||||
"desc":"Returns the semantic version of the public API, which is maintained separate from the app version.",
|
||||
"returnType":"string",
|
||||
"url":"/version",
|
||||
"desc":"Returns the semantic version of the public API, which is maintained separate from the app version."
|
||||
},
|
||||
|
||||
]
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ const forceCsrf = csurf({ ignoreMethods: [] });
|
|||
|
||||
router.get("/docs", function(req, res, next) {
|
||||
res.locals.apiDocs = apiDocs;
|
||||
res.locals.apiBaseUrl = apiDocs.baseUrl;
|
||||
res.locals.route = req.query.route;
|
||||
|
||||
res.locals.categories = [];
|
||||
|
|
@ -73,11 +74,14 @@ router.get("/version", function(req, res, next) {
|
|||
|
||||
/// BLOCKS
|
||||
|
||||
router.get("/blocks/tip/height", asyncHandler(async (req, res, next) => {
|
||||
router.get("/blocks/tip", asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
const blockcount = await rpcApi.getBlockCount();
|
||||
const getblockchaininfo = await coreApi.getBlockchainInfo();
|
||||
|
||||
res.send(blockcount.toString());
|
||||
res.send({
|
||||
height: getblockchaininfo.blocks,
|
||||
hash: getblockchaininfo.bestblockhash
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
utils.logError("a39gfoeuew", e);
|
||||
|
|
@ -88,12 +92,6 @@ router.get("/blocks/tip/height", asyncHandler(async (req, res, next) => {
|
|||
next();
|
||||
}));
|
||||
|
||||
router.get("/blocks/tip/hash", function(req, res, next) {
|
||||
coreApi.getBlockchainInfo().then(function(getblockchaininfo){
|
||||
res.send(getblockchaininfo.bestblockhash.toString());
|
||||
}).catch(next);
|
||||
});
|
||||
|
||||
router.get("/block/:hashOrHeight", asyncHandler(async (req, res, next) => {
|
||||
const hashOrHeight = req.params.hashOrHeight;
|
||||
let hash = (hashOrHeight.length == 64 ? hashOrHeight : null);
|
||||
|
|
@ -221,22 +219,33 @@ router.get("/tx/volume/24h", function(req, res, next) {
|
|||
|
||||
/// BLOCKCHAIN
|
||||
|
||||
router.get("/blockchain/coins", function(req, res, next) {
|
||||
router.get("/blockchain/coins", asyncHandler(async (req, res, next) => {
|
||||
if (global.utxoSetSummary) {
|
||||
let supply = parseFloat(global.utxoSetSummary.total_amount).toString();
|
||||
|
||||
res.send(supply.toString());
|
||||
res.send({
|
||||
supply: supply.toString(),
|
||||
type: "calculated"
|
||||
});
|
||||
|
||||
next();
|
||||
|
||||
} else {
|
||||
// estimated supply
|
||||
coreApi.getBlockchainInfo().then(function(getblockchaininfo){
|
||||
let estimatedSupply = utils.estimatedSupply(getblockchaininfo.blocks);
|
||||
res.send(estimatedSupply.toString());
|
||||
}).catch(next);
|
||||
|
||||
let getblockchaininfo = await coreApi.getBlockchainInfo();
|
||||
let estimatedSupply = utils.estimatedSupply(getblockchaininfo.blocks);
|
||||
let lastCheckpoint = coinConfig.utxoSetCheckpointsByNetwork[global.activeBlockchain];
|
||||
|
||||
res.send({
|
||||
supply: estimatedSupply.toString(),
|
||||
type: "estimated",
|
||||
lastCheckpointHeight: lastCheckpoint.height
|
||||
})
|
||||
|
||||
next();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
router.get("/blockchain/utxo-set", asyncHandler(async (req, res, next) => {
|
||||
const utxoSetSummary = await coreApi.getUtxoSetSummary(true, true);
|
||||
|
|
@ -246,6 +255,68 @@ router.get("/blockchain/utxo-set", asyncHandler(async (req, res, next) => {
|
|||
next();
|
||||
}));
|
||||
|
||||
router.get("/blockchain/next-halving", asyncHandler(async (req, res, next) => {
|
||||
try {
|
||||
const getblockchaininfo = await coreApi.getBlockchainInfo();
|
||||
|
||||
let promises = [];
|
||||
|
||||
res.locals.getblockchaininfo = getblockchaininfo;
|
||||
res.locals.difficultyPeriod = parseInt(Math.floor(getblockchaininfo.blocks / coinConfig.difficultyAdjustmentBlockCount));
|
||||
|
||||
let blockHeights = [];
|
||||
if (getblockchaininfo.blocks) {
|
||||
for (let i = 0; i < 1; i++) {
|
||||
blockHeights.push(getblockchaininfo.blocks - i);
|
||||
}
|
||||
} else if (global.activeBlockchain == "regtest") {
|
||||
// hack: default regtest node returns getblockchaininfo.blocks=0, despite
|
||||
// having a genesis block; hack this to display the genesis block
|
||||
blockHeights.push(0);
|
||||
}
|
||||
|
||||
promises.push(utils.timePromise("homepage.getBlockHeaderByHeight", async () => {
|
||||
let h = coinConfig.difficultyAdjustmentBlockCount * res.locals.difficultyPeriod;
|
||||
res.locals.difficultyPeriodFirstBlockHeader = await coreApi.getBlockHeaderByHeight(h);
|
||||
}));
|
||||
|
||||
promises.push(utils.timePromise("homepage.getBlocksByHeight", async () => {
|
||||
const latestBlocks = await coreApi.getBlocksByHeight(blockHeights);
|
||||
|
||||
res.locals.latestBlocks = latestBlocks;
|
||||
}));
|
||||
|
||||
await utils.awaitPromises(promises);
|
||||
|
||||
|
||||
let nextHalvingData = utils.nextHalvingEstimates(res.locals.difficultyPeriodFirstBlockHeader, res.locals.latestBlocks[0]);
|
||||
|
||||
// timeAgo = moment.duration(moment.utc(new Date()).diff(moment.utc(new Date())));
|
||||
let timeAgo = moment.duration(moment.utc(nextHalvingData.nextHalvingDate).diff(moment.utc(new Date())));
|
||||
let format = timeAgo.format();
|
||||
let formatParts = format.split(",").map(x => x.trim());
|
||||
formatParts = formatParts.map(x => { return x.startsWith("0 ") ? "" : x; }).filter(x => x.length > 0);
|
||||
|
||||
res.json({
|
||||
nextHalvingIndex: nextHalvingData.nextHalvingIndex,
|
||||
nextHalvingBlock: nextHalvingData.nextHalvingBlock,
|
||||
nextHalvingSubsidy: coinConfig.blockRewardFunction(nextHalvingData.nextHalvingBlock, global.activeBlockchain),
|
||||
blocksUntilNextHalving: nextHalvingData.blocksUntilNextHalving,
|
||||
timeUntilNextHalving: formatParts.join(", "),
|
||||
nextHalvingEstimatedDate: nextHalvingData.nextHalvingDate,
|
||||
});
|
||||
|
||||
next();
|
||||
|
||||
} catch (e) {
|
||||
utils.logError("013923hege3", e)
|
||||
|
||||
res.json({success:false});
|
||||
|
||||
next();
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -793,12 +864,6 @@ router.get("/mining/miner-summary", asyncHandler(async (req, res, next) => {
|
|||
|
||||
/// MEMPOOL
|
||||
|
||||
router.get("/mempool/count", function(req, res, next) {
|
||||
coreApi.getMempoolInfo().then(function(info){
|
||||
res.send(info.size.toString());
|
||||
}).catch(next);
|
||||
});
|
||||
|
||||
router.get("/mempool/summary", function(req, res, next) {
|
||||
coreApi.getMempoolInfo().then(function(info){
|
||||
res.json(info);
|
||||
|
|
@ -840,30 +905,35 @@ router.get("/mempool/fees", function(req, res, next) {
|
|||
|
||||
/// PRICE
|
||||
|
||||
router.get("/price/:currency/sats", function(req, res, next) {
|
||||
let result = 0;
|
||||
let amount = 1.0;
|
||||
let currency = req.params.currency.toLowerCase();
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let satsRateData = utils.satoshisPerUnitOfLocalCurrency(currency);
|
||||
result = satsRateData.amtRaw;
|
||||
const supportedCurrencies = ["usd", "eur", "gbp", "xau"];
|
||||
|
||||
} else if (currency == "xau" && global.exchangeRates != null && global.goldExchangeRates != null) {
|
||||
let dec = new Decimal(amount);
|
||||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
let satCurrencyType = global.currencyTypes["sat"];
|
||||
let one = new Decimal(1);
|
||||
dec = one.dividedBy(dec);
|
||||
dec = dec.times(satCurrencyType.multiplier);
|
||||
|
||||
result = dec.toFixed(0);
|
||||
}
|
||||
router.get("/price/sats", function(req, res, next) {
|
||||
let result = {};
|
||||
let amount = 1.0;
|
||||
|
||||
supportedCurrencies.forEach(currency => {
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let satsRateData = utils.satoshisPerUnitOfLocalCurrency(currency);
|
||||
result[currency] = satsRateData.amtRaw;
|
||||
|
||||
} else if (currency == "xau" && global.exchangeRates != null && global.goldExchangeRates != null) {
|
||||
let dec = new Decimal(amount);
|
||||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
let satCurrencyType = global.currencyTypes["sat"];
|
||||
let one = new Decimal(1);
|
||||
dec = one.dividedBy(dec);
|
||||
dec = dec.times(satCurrencyType.multiplier);
|
||||
|
||||
result[currency] = dec.toFixed(0);
|
||||
}
|
||||
});
|
||||
|
||||
res.send(result.toString());
|
||||
res.json(result);
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
router.get("/price/:currency/marketcap", function(req, res, next) {
|
||||
router.get("/price/marketcap", function(req, res, next) {
|
||||
let result = 0;
|
||||
|
||||
coreApi.getBlockchainInfo().then(function(getblockchaininfo){
|
||||
|
|
@ -871,58 +941,36 @@ router.get("/price/:currency/marketcap", function(req, res, next) {
|
|||
let price = 0;
|
||||
|
||||
let amount = 1.0;
|
||||
let currency = req.params.currency.toLowerCase();
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let formatData = utils.formatExchangedCurrency(amount, currency);
|
||||
price = parseFloat(formatData.valRaw).toFixed(2);
|
||||
let result = {};
|
||||
|
||||
supportedCurrencies.forEach(currency => {
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let formatData = utils.formatExchangedCurrency(amount, currency);
|
||||
price = parseFloat(formatData.valRaw).toFixed(2);
|
||||
|
||||
} else if (currency == "xau" && global.exchangeRates != null && global.goldExchangeRates != null) {
|
||||
let dec = new Decimal(amount);
|
||||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
let exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
|
||||
price = exchangedAmt;
|
||||
}
|
||||
|
||||
result[currency] = estimatedSupply * price;
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
|
||||
} else if (currency == "xau" && global.exchangeRates != null && global.goldExchangeRates != null) {
|
||||
let dec = new Decimal(amount);
|
||||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
let exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
|
||||
price = exchangedAmt;
|
||||
}
|
||||
|
||||
result = estimatedSupply * price;
|
||||
res.send(result.toFixed(2).toString());
|
||||
next();
|
||||
|
||||
}).catch(next);
|
||||
});
|
||||
|
||||
router.get("/price/:currency", function(req, res, next) {
|
||||
let result = 0;
|
||||
let amount = 1.0;
|
||||
let currency = req.params.currency.toLowerCase();
|
||||
let format = (req.query.format == "true");
|
||||
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let formatData = utils.formatExchangedCurrency(amount, currency);
|
||||
|
||||
if (format) {
|
||||
result = formatData.val;
|
||||
|
||||
} else {
|
||||
result = formatData.valRaw;
|
||||
}
|
||||
} else if (currency == "xau" && global.exchangeRates != null && global.goldExchangeRates != null) {
|
||||
let dec = new Decimal(amount);
|
||||
dec = dec.times(global.exchangeRates.usd).dividedBy(global.goldExchangeRates.usd);
|
||||
let exchangedAmt = parseFloat(Math.round(dec * 100) / 100).toFixed(2);
|
||||
result = utils.addThousandsSeparators(exchangedAmt);
|
||||
}
|
||||
|
||||
res.send(result.toString());
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
router.get("/price", function(req, res, next) {
|
||||
let amount = 1.0;
|
||||
let result = {};
|
||||
let format = (req.query.format == "true");
|
||||
|
||||
["usd", "eur", "gbp", "xau"].forEach(currency => {
|
||||
supportedCurrencies.forEach(currency => {
|
||||
if (global.exchangeRates != null && global.exchangeRates[currency] != null) {
|
||||
let formatData = utils.formatExchangedCurrency(amount, currency);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ block headContent
|
|||
block content
|
||||
+pageTitle("API Docs")
|
||||
div.fs-4.mt-n3.mb-3 Current Version:
|
||||
a.ms-2(href="./api/version", title="View version API call: /api/version", data-bs-toggle="tooltip", target="_blank") v#{apiDocs.version}
|
||||
a.ms-2(href=`.${apiBaseUrl}/version`, title=`View version API call: ${apiBaseUrl}/version`, data-bs-toggle="tooltip", target="_blank") v#{apiDocs.version}
|
||||
small.ms-2 (
|
||||
a(href="./api/changelog") changelog
|
||||
a(href=`.${apiBaseUrl}/changelog`) changelog
|
||||
| )
|
||||
|
||||
if (false)
|
||||
|
|
@ -19,7 +19,7 @@ block content
|
|||
+dismissableInfoAlert("apiDocsNoteDismissed", "About the API...")
|
||||
h6.mb-2 About the API
|
||||
|
||||
| The API documented below is made available by btc-rpc-explorer. The actions are organized by category. From this documentation you can directly click on an action's link to see the output format in your browser.
|
||||
| The API documented below is made available by btc-rpc-explorer. All actions return JSON content. The actions are organized by category. From this documentation you can directly click on an action's link to see the output format in your browser.
|
||||
|
||||
|
||||
each cat, catIndex in categories
|
||||
|
|
@ -32,13 +32,9 @@ block content
|
|||
|
||||
.row.p-2
|
||||
.col-md-3
|
||||
a(href=(item.testUrl ? `.${item.testUrl}` : `.${item.url}`), target="_blank") #{item.url}
|
||||
a(href=(item.testUrl ? `.${apiBaseUrl}${item.testUrl}` : `.${apiBaseUrl}${item.url}`), target="_blank") #{apiBaseUrl}#{item.url}
|
||||
|
||||
.col-md-1
|
||||
span(title=`Return type: ${item.returnType}`, data-bs-toggle="tooltip")
|
||||
+lightBadge(item.returnType)
|
||||
|
||||
.col-md-8
|
||||
.col-md-9
|
||||
|
||||
div #{item.desc}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue