mirror of
https://github.com/mempool/mempool.git
synced 2025-09-27 18:47:09 +02:00
Merge pull request #5969 from mempool/mononaut/fix-fee-recommendations
fix fee recommendations
This commit is contained in:
55
backend/src/__tests__/api/fee-api.ts
Normal file
55
backend/src/__tests__/api/fee-api.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import feeApi from '../../api/fee-api';
|
||||||
|
import { IBitcoinApi } from '../../api/bitcoin/bitcoin-api.interface';
|
||||||
|
const feeMempoolBlocks = require('./test-data/fee-mempool-blocks.json');
|
||||||
|
|
||||||
|
|
||||||
|
const subSatMempoolInfo: IBitcoinApi.MempoolInfo = {
|
||||||
|
mempoolminfee: 0.000001, // 0.1 sat/vbyte
|
||||||
|
loaded: true,
|
||||||
|
size: 100,
|
||||||
|
bytes: 10000,
|
||||||
|
usage: 10000,
|
||||||
|
total_fee: 10000,
|
||||||
|
maxmempool: 10000,
|
||||||
|
minrelaytxfee: 0.000001, // 0.1 sat/vbyte
|
||||||
|
};
|
||||||
|
|
||||||
|
const mempoolInfo: IBitcoinApi.MempoolInfo = {
|
||||||
|
mempoolminfee: 0.00001,
|
||||||
|
loaded: true,
|
||||||
|
size: 100,
|
||||||
|
bytes: 10000,
|
||||||
|
usage: 10000,
|
||||||
|
total_fee: 10000,
|
||||||
|
maxmempool: 10000,
|
||||||
|
minrelaytxfee: 0.00001,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Fee API', () => {
|
||||||
|
test('should calculate recommended fees properly for sub-sat mempool', () => {
|
||||||
|
const fee = feeApi.calculateRecommendedFee(feeMempoolBlocks.subsat, subSatMempoolInfo);
|
||||||
|
expect(fee.fastestFee).toBe(2);
|
||||||
|
expect(fee.halfHourFee).toBe(1);
|
||||||
|
expect(fee.hourFee).toBe(1);
|
||||||
|
expect(fee.economyFee).toBe(1);
|
||||||
|
expect(fee.minimumFee).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should calculate recommended fees properly for full but low fee mempool', () => {
|
||||||
|
const fee = feeApi.calculateRecommendedFee(feeMempoolBlocks.lowfee, mempoolInfo);
|
||||||
|
expect(fee.fastestFee).toBe(2);
|
||||||
|
expect(fee.halfHourFee).toBe(2);
|
||||||
|
expect(fee.hourFee).toBe(2);
|
||||||
|
expect(fee.economyFee).toBe(2);
|
||||||
|
expect(fee.minimumFee).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should calculate recommended fees properly for empty mempool', () => {
|
||||||
|
const fee = feeApi.calculateRecommendedFee(feeMempoolBlocks.empty, mempoolInfo);
|
||||||
|
expect(fee.fastestFee).toBe(1);
|
||||||
|
expect(fee.halfHourFee).toBe(1);
|
||||||
|
expect(fee.hourFee).toBe(1);
|
||||||
|
expect(fee.economyFee).toBe(1);
|
||||||
|
expect(fee.minimumFee).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
289
backend/src/__tests__/api/test-data/fee-mempool-blocks.json
Normal file
289
backend/src/__tests__/api/test-data/fee-mempool-blocks.json
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
{
|
||||||
|
"subsat": [
|
||||||
|
{
|
||||||
|
"blockSize": 1746106,
|
||||||
|
"blockVSize": 997953.25,
|
||||||
|
"nTx": 3750,
|
||||||
|
"totalFees": 1764766,
|
||||||
|
"medianFee": 1.0023586640951265,
|
||||||
|
"feeRange": [
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123,
|
||||||
|
1.2076788830715532,
|
||||||
|
3.166077738515901,
|
||||||
|
73.61111111111111
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 1809871,
|
||||||
|
"blockVSize": 997963,
|
||||||
|
"nTx": 4861,
|
||||||
|
"totalFees": 588436,
|
||||||
|
"medianFee": 0.6082474226804123,
|
||||||
|
"feeRange": [
|
||||||
|
0.5156626506024097,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5670103092783505,
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123,
|
||||||
|
0.6082474226804123
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 2917870,
|
||||||
|
"blockVSize": 997821.25,
|
||||||
|
"nTx": 1221,
|
||||||
|
"totalFees": 535389,
|
||||||
|
"medianFee": 0.5200034509958588,
|
||||||
|
"feeRange": [
|
||||||
|
0.35051546391752575,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5649475055559813,
|
||||||
|
0.5649475055559813
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3937966,
|
||||||
|
"blockVSize": 997875.25,
|
||||||
|
"nTx": 18,
|
||||||
|
"totalFees": 506205,
|
||||||
|
"medianFee": 0.5100003123470801,
|
||||||
|
"feeRange": [
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.5099980684971892,
|
||||||
|
0.5100003123470801,
|
||||||
|
0.5100020185186144,
|
||||||
|
0.5100025244589157
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3917639,
|
||||||
|
"blockVSize": 997810.25,
|
||||||
|
"nTx": 62,
|
||||||
|
"totalFees": 503529,
|
||||||
|
"medianFee": 0.5099975959779666,
|
||||||
|
"feeRange": [
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.5099971889756266,
|
||||||
|
0.5100002265056967
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3694897,
|
||||||
|
"blockVSize": 997893.25,
|
||||||
|
"nTx": 43,
|
||||||
|
"totalFees": 503307,
|
||||||
|
"medianFee": 0.5099952023028946,
|
||||||
|
"feeRange": [
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.3704911425797351,
|
||||||
|
0.5099952023028946,
|
||||||
|
0.5099967157103613
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 2486759,
|
||||||
|
"blockVSize": 997857.5,
|
||||||
|
"nTx": 498,
|
||||||
|
"totalFees": 386911,
|
||||||
|
"medianFee": 0.36001120750903104,
|
||||||
|
"feeRange": [
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.5000054632270189
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 6681226,
|
||||||
|
"blockVSize": 3385616.5,
|
||||||
|
"nTx": 10222,
|
||||||
|
"totalFees": 1197838,
|
||||||
|
"medianFee": 0.35051546391752575,
|
||||||
|
"feeRange": [
|
||||||
|
0.21576460085542437,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.35051546391752575,
|
||||||
|
0.3599967979827291,
|
||||||
|
0.3600004002561639,
|
||||||
|
0.3600040026016911,
|
||||||
|
0.3600040026016911,
|
||||||
|
0.3600040026016911
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"empty": [{
|
||||||
|
"blockSize": 10000,
|
||||||
|
"blockVSize": 10000,
|
||||||
|
"nTx": 2000,
|
||||||
|
"totalFees": 1197838,
|
||||||
|
"medianFee": 1,
|
||||||
|
"feeRange": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"lowfee": [
|
||||||
|
{
|
||||||
|
"blockSize": 1746106,
|
||||||
|
"blockVSize": 997953.25,
|
||||||
|
"nTx": 3750,
|
||||||
|
"totalFees": 1764766,
|
||||||
|
"medianFee": 1.0023586640951265,
|
||||||
|
"feeRange": [
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.2076788830715532,
|
||||||
|
3.166077738515901,
|
||||||
|
73.61111111111111
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 1809871,
|
||||||
|
"blockVSize": 997963,
|
||||||
|
"nTx": 4861,
|
||||||
|
"totalFees": 588436,
|
||||||
|
"medianFee": 1.6082474226804123,
|
||||||
|
"feeRange": [
|
||||||
|
1.5156626506024097,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5670103092783505,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123,
|
||||||
|
1.6082474226804123
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 2917870,
|
||||||
|
"blockVSize": 997821.25,
|
||||||
|
"nTx": 1221,
|
||||||
|
"totalFees": 535389,
|
||||||
|
"medianFee": 1.5200034509958588,
|
||||||
|
"feeRange": [
|
||||||
|
1.35051546391752575,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5649475055559813,
|
||||||
|
1.5649475055559813
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3937966,
|
||||||
|
"blockVSize": 997875.25,
|
||||||
|
"nTx": 18,
|
||||||
|
"totalFees": 506205,
|
||||||
|
"medianFee": 1.5100003123470801,
|
||||||
|
"feeRange": [
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.5099980684971892,
|
||||||
|
1.5100003123470801,
|
||||||
|
1.5100020185186144,
|
||||||
|
1.5100025244589157
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3917639,
|
||||||
|
"blockVSize": 997811.25,
|
||||||
|
"nTx": 62,
|
||||||
|
"totalFees": 503529,
|
||||||
|
"medianFee": 1.5099975959779666,
|
||||||
|
"feeRange": [
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.5099971889756266,
|
||||||
|
1.5100002265056967
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 3694897,
|
||||||
|
"blockVSize": 997893.25,
|
||||||
|
"nTx": 43,
|
||||||
|
"totalFees": 503307,
|
||||||
|
"medianFee": 1.5099952023028946,
|
||||||
|
"feeRange": [
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.3704911425797351,
|
||||||
|
1.5099952023028946,
|
||||||
|
1.5099967157103613
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 2486759,
|
||||||
|
"blockVSize": 997857.5,
|
||||||
|
"nTx": 498,
|
||||||
|
"totalFees": 386911,
|
||||||
|
"medianFee": 1.36001120750903104,
|
||||||
|
"feeRange": [
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.5000054632270189
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockSize": 6681226,
|
||||||
|
"blockVSize": 3385616.5,
|
||||||
|
"nTx": 10222,
|
||||||
|
"totalFees": 1197838,
|
||||||
|
"medianFee": 1.35051546391752575,
|
||||||
|
"feeRange": [
|
||||||
|
1.21576460085542437,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.35051546391752575,
|
||||||
|
1.3599967979827291,
|
||||||
|
1.3600004002561639,
|
||||||
|
1.3600040026016911,
|
||||||
|
1.3600040026016911,
|
||||||
|
1.3600040026016911
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
import { MempoolBlock } from '../mempool.interfaces';
|
import { MempoolBlock } from '../mempool.interfaces';
|
||||||
|
import { IBitcoinApi } from './bitcoin/bitcoin-api.interface';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import mempool from './mempool';
|
import mempool from './mempool';
|
||||||
import projectedBlocks from './mempool-blocks';
|
import projectedBlocks from './mempool-blocks';
|
||||||
@@ -22,6 +23,11 @@ class FeeApi {
|
|||||||
public getRecommendedFee(): RecommendedFees {
|
public getRecommendedFee(): RecommendedFees {
|
||||||
const pBlocks = projectedBlocks.getMempoolBlocks();
|
const pBlocks = projectedBlocks.getMempoolBlocks();
|
||||||
const mPool = mempool.getMempoolInfo();
|
const mPool = mempool.getMempoolInfo();
|
||||||
|
|
||||||
|
return this.calculateRecommendedFee(pBlocks, mPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public calculateRecommendedFee(pBlocks: MempoolBlock[], mPool: IBitcoinApi.MempoolInfo): RecommendedFees {
|
||||||
const minimumFee = this.roundUpToNearest(mPool.mempoolminfee * 100000, this.minimumIncrement);
|
const minimumFee = this.roundUpToNearest(mPool.mempoolminfee * 100000, this.minimumIncrement);
|
||||||
const defaultMinFee = Math.max(minimumFee, this.defaultFee);
|
const defaultMinFee = Math.max(minimumFee, this.defaultFee);
|
||||||
|
|
||||||
@@ -64,7 +70,7 @@ class FeeApi {
|
|||||||
|
|
||||||
private optimizeMedianFee(pBlock: MempoolBlock, nextBlock: MempoolBlock | undefined, previousFee?: number): number {
|
private optimizeMedianFee(pBlock: MempoolBlock, nextBlock: MempoolBlock | undefined, previousFee?: number): number {
|
||||||
const useFee = previousFee ? (pBlock.medianFee + previousFee) / 2 : pBlock.medianFee;
|
const useFee = previousFee ? (pBlock.medianFee + previousFee) / 2 : pBlock.medianFee;
|
||||||
if (pBlock.blockVSize <= 500000) {
|
if (pBlock.blockVSize <= 500000 || pBlock.medianFee < 1) {
|
||||||
return this.defaultFee;
|
return this.defaultFee;
|
||||||
}
|
}
|
||||||
if (pBlock.blockVSize <= 950000 && !nextBlock) {
|
if (pBlock.blockVSize <= 950000 && !nextBlock) {
|
||||||
|
Reference in New Issue
Block a user