From 3362028f665554da5eee1cf8e42c1d2d67785c99 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 24 Dec 2023 15:51:20 +0700 Subject: [PATCH] Use blockstream api for further future estimates --- README.md | 30 +++++++++++++++++++++++++++--- src/server.js | 30 ++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2cd11c2..fe111d0 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,34 @@ # Lnd Mempool.Space Integration -This project aims to integrate the [Lightning Network Daemon (lnd)](https://github.com/lightningnetwork/lnd) with [mempool.space](https://mempool.space/), a Bitcoin blockchain explorer. The primary feature of this integration is to provide fee estimates to lnd based on the fee estimates from mempool.space. +This project aims to integrate the [Lightning Network Daemon (lnd)](https://github.com/lightningnetwork/lnd) with [mempool.space](https://mempool.space/), a Bitcoin blockchain explorer. The primary feature of this integration is to provide fee estimates to lnd based on a combination of mempool-based estimates (from the mempool.space API) and history-based estimates (from the Blockstream API). -## Features +## Fee Estimates -- Fee Estimates: The integration fetches fee estimates from mempool.space and provides them to lnd. +This application uses two APIs to get fee estimates for Bitcoin transactions: + +- [**mempool.space API**](https://mempool.space/docs/api/rest): This API is used to get mempool-based fee estimates for upcoming blocks. The application fetches the fastestFee, halfHourFee, hourFee, economyFee, and minimumFee from the mempool.space API and uses these estimates to calculate the fee for upcoming blocks. The application also multiplies these estimates by a configurable multiplier to ensure that can be used to ensure that the fee estimates are always slightly higher or lower than the mempool.space estimates. + +- [**Blockstream API**](https://github.com/Blockstream/esplora/blob/master/API.md): This API is used to get history-based fee estimates for further future blocks. The application fetches the fee estimates from the Blockstream API (which gets its data from bitcoind) and adds them to the fee estimates if they are lower than the lowest fee estimate from the mempool.space API. + +Fee estimates are cached for a configurable amount of time (15 seconds by default) to reduce the number of API calls. The cache is automatically cleared after the configured time has elapsed. + +## API + +This application exposes a single API endpoint at `/v1/fee-estimates.json`. This endpoint returns a JSON object with the following structure, which is compatible with the LND's `feeurl` setting: + +```json +{ + "current_block_hash": "0000000000000000000044ab897830778c73d33fdeddde1f21e875fae2150378", + "fee_by_block_target": { + "1": 81900, + "2": 78750, + "3": 74550, + "144": 64951, + "504": 53464, + "1008": 28175 + } +} +``` ## Setup & Usage diff --git a/src/server.js b/src/server.js index 235575f..188bfff 100644 --- a/src/server.js +++ b/src/server.js @@ -55,31 +55,41 @@ app.get('/v1/fee-estimates.json', async (req, res) => { // Check if the response is cached. let data = myCache.get('data'); - // If the response is not cached, fetch it from the mempool.space API. + // If the response is not cached, fetch it . if (!data) { // Fetch the current block hash. const { bitcoin: { blocks } } = mempool; const blocksTipHash = await blocks.getBlocksTipHash(); - // Fetch fee estimates. + // Fetch fee estimates from mempool.space API. const { bitcoin: { fees } } = mempool; const feeEstimates = await fees.getFeesRecommended(); - const mempoolBlocks = await fees.getFeesMempoolBlocks(); - const minFee = feeEstimates.minimumFee * feeMultiplier; + // Fetch fee estimates from Blockstream API. + const blockstreamFeeEstimates = await fetch('https://blockstream.info/api/fee-estimates'); + const blockstreamFees = await blockstreamFeeEstimates.json(); - // Transform the fee estimates to match the desired format. + // Get the minimum fee from mempool.space (we use their economy rate). + const minFee = feeEstimates.economyFee; + + // Use mempool.space fee estimates for upcoming blocks. const feeByBlockTarget = { 1: Math.round(feeEstimates.fastestFee * 1000 * feeMultiplier), 2: Math.round(feeEstimates.halfHourFee * 1000 * feeMultiplier), // usually between first and second block 3: Math.round(feeEstimates.hourFee * 1000 * feeMultiplier), // usually between second and third block - 36: Math.max(Math.round(mempoolBlocks[2].medianFee * 1000 * feeMultiplier), minFee), // 6 hours to get 3 blocks deep - 72: Math.max(Math.round(mempoolBlocks[4].medianFee * 1000 * feeMultiplier), minFee), // 12 hours to get 5 blocks deep - 144: Math.max(Math.round(mempoolBlocks[6].medianFee * 1000 * feeMultiplier), minFee), // 24 hours to get 7 blocks deep - 720: Math.round(feeEstimates.economyFee * 1000 * feeMultiplier), // 5 days to get to 2x above economy - 1008: Math.round(feeEstimates.minimumFee * 1000 * feeMultiplier) // 7 days to get to the minimum fee }; + // Calculate the minimum fee from the feeByBlockTarget object. + const minMempoolFee = Math.min(...Object.values(feeByBlockTarget)); + + // Merge Blockstream fee estimates into feeByBlockTarget. + for (const [blockTarget, fee] of Object.entries(blockstreamFees)) { + const adjustedFee = Math.round(fee * 1000); + if (!feeByBlockTarget.hasOwnProperty(blockTarget) && adjustedFee < minMempoolFee) { + feeByBlockTarget[blockTarget] = adjustedFee; + } + } + // Create the response object. data = { current_block_hash: blocksTipHash,