diff --git a/packages/bitcore-node/src/providers/chain-state/internal/internal.ts b/packages/bitcore-node/src/providers/chain-state/internal/internal.ts index 2a9bc632198..80bef3768dc 100644 --- a/packages/bitcore-node/src/providers/chain-state/internal/internal.ts +++ b/packages/bitcore-node/src/providers/chain-state/internal/internal.ts @@ -459,12 +459,12 @@ export class InternalStateProvider implements IChainStateService { } async getFee(params: GetEstimateSmartFeeParams) { - const { chain, network, target } = params; - const cacheKey = `getFee-${chain}-${network}-${target}`; + const { chain, network, target, mode } = params; + const cacheKey = `getFee-${chain}-${network}-${target}${mode ? '-' + mode.toLowerCase() : ''}`; return CacheStorage.getGlobalOrRefresh( cacheKey, async () => { - return this.getRPC(chain, network).getEstimateSmartFee(Number(target)); + return this.getRPC(chain, network).getEstimateSmartFee(Number(target), mode); }, 5 * CacheStorage.Times.Minute ); diff --git a/packages/bitcore-node/src/routes/api/fee.ts b/packages/bitcore-node/src/routes/api/fee.ts index 0124bef90d9..d53400a827d 100644 --- a/packages/bitcore-node/src/routes/api/fee.ts +++ b/packages/bitcore-node/src/routes/api/fee.ts @@ -1,22 +1,45 @@ import { Request, Response } from 'express'; +import config from '../../config'; +import logger from '../../logger'; import { ChainStateProvider } from '../../providers/chain-state'; +import { IUtxoNetworkConfig } from '../../types/Config'; import { CacheTimes } from '../middleware'; import { CacheMiddleware } from '../middleware'; const router = require('express').Router({ mergeParams: true }); const feeCache = {}; +const feeModes = { + BTC: ['CONSERVATIVE', 'ECONOMICAL'], + LTC: ['CONSERVATIVE', 'ECONOMICAL'] +}; + router.get('/:target', CacheMiddleware(CacheTimes.Second), async (req: Request, res: Response) => { let { target, chain, network } = req.params; + let { mode } = req.query; + if (!chain || !network) { + return res.status(400).send('Missing required param'); + } + chain = chain.toUpperCase(); + network = network.toLowerCase(); + mode = mode?.toUpperCase(); const targetNum = Number(target); if (targetNum < 0 || targetNum > 100) { return res.status(400).send('invalid target specified'); } - const cachedFee = feeCache[`${chain}:${network}:${target}`]; + if (!mode) { + mode = (config.chains[chain]?.[network] as IUtxoNetworkConfig)?.defaultFeeMode; + } else if (!feeModes[chain]) { + mode = undefined; + } else if (!feeModes[chain]?.includes(mode)) { + return res.status(400).send('invalid mode specified'); + } + const feeCacheKey = `${chain}:${network}:${target}${mode ? ':' + mode : ''}`; + const cachedFee = feeCache[feeCacheKey]; if (cachedFee && cachedFee.date > Date.now() - 10 * 1000) { return res.json(cachedFee.fee); } try { - let fee = await ChainStateProvider.getFee({ chain, network, target: targetNum }); + let fee = await ChainStateProvider.getFee({ chain, network, target: targetNum, mode }); if (!fee) { return res.status(404).send('not available right now'); } @@ -25,9 +48,10 @@ router.get('/:target', CacheMiddleware(CacheTimes.Second), async (req: Request, if (chain === 'LTC' && fee.feerate && fee.feerate < 0.00001) { fee.feerate = 0.00001; } - feeCache[`${chain}:${network}:${target}`] = { fee, date: Date.now() }; + feeCache[feeCacheKey] = { fee, date: Date.now() }; return res.json(fee); - } catch (err) { + } catch (err: any) { + logger.error('Fee Error: %o', err.message || err); return res.status(500).send('Error getting fee from RPC'); } }); diff --git a/packages/bitcore-node/src/rpc.ts b/packages/bitcore-node/src/rpc.ts index 1b442350dc3..3fc69e9d6eb 100644 --- a/packages/bitcore-node/src/rpc.ts +++ b/packages/bitcore-node/src/rpc.ts @@ -103,8 +103,12 @@ export class RPC { return this.asyncCall('getaddressesbyaccount', [account]); } - async getEstimateSmartFee(target: number) { - return this.asyncCall('estimatesmartfee', [target]); + async getEstimateSmartFee(target: number, mode?: string) { + const args: any[] = [target]; + if (mode) { + args.push(mode); + } + return this.asyncCall('estimatesmartfee', args); } async getEstimateFee() { diff --git a/packages/bitcore-node/src/types/Config.ts b/packages/bitcore-node/src/types/Config.ts index def8e7986f0..d09799eea00 100644 --- a/packages/bitcore-node/src/types/Config.ts +++ b/packages/bitcore-node/src/types/Config.ts @@ -20,6 +20,7 @@ export interface IUtxoNetworkConfig extends INetworkConfig { username: string; password: string; }; + defaultFeeMode?: 'CONSERVATIVE' | 'ECONOMICAL'; } interface IProvider { diff --git a/packages/bitcore-node/src/types/namespaces/ChainStateProvider.ts b/packages/bitcore-node/src/types/namespaces/ChainStateProvider.ts index fa2be0a5344..11619f640e2 100644 --- a/packages/bitcore-node/src/types/namespaces/ChainStateProvider.ts +++ b/packages/bitcore-node/src/types/namespaces/ChainStateProvider.ts @@ -55,6 +55,7 @@ export type StreamBlocksParams = ChainNetwork & { }; export type GetEstimateSmartFeeParams = ChainNetwork & { target: number; + mode?: 'ECONOMICAL' | 'CONSERVATIVE'; }; export type BroadcastTransactionParams = ChainNetwork & { rawTx: string | Array;