diff --git a/.github/workflows/dev.yml b/.github/workflows/main.yml similarity index 99% rename from .github/workflows/dev.yml rename to .github/workflows/main.yml index a0b86dc..33c17b8 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: Dev +name: Main on: push: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bb837f6..8de1026 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,8 @@ name: Test on: push: + branches-ignore: + - master jobs: publish: diff --git a/src/util.ts b/src/util.ts index 042e373..fb59a6a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -360,12 +360,17 @@ export async function getEstimates(): Promise { const bitcoindFeeEstimates = getValueFromFulfilledPromise(result3); const blocksTipHash = getValueFromFulfilledPromise(result4); + // Get the minimum fee. If the mempool fee estimates are not available, use a default value of FEE_MINIMUM sat/vbyte as a safety net. + const feeMinimum = (mempoolFeeEstimates?.minimumFee ?? FEE_MINIMUM) * 1000; + log.info({ message: "Using minimum fee: {feeMinimum}", feeMinimum }); + estimates = { current_block_hash: blocksTipHash, fee_by_block_target: calculateFees( mempoolFeeEstimates, esploraFeeEstimates, bitcoindFeeEstimates, + feeMinimum, ), }; @@ -380,6 +385,7 @@ export async function getEstimates(): Promise { */ export function extractMempoolFees( mempoolFeeEstimates: MempoolFeeEstimates, + depth: number, ): FeeByBlockTarget { const feeByBlockTarget: FeeByBlockTarget = {}; @@ -389,7 +395,7 @@ export function extractMempoolFees( 3: "halfHourFee", 6: "hourFee", }; - for (let i = 1; i <= MEMPOOL_DEPTH; i++) { + for (let i = 1; i <= depth; i++) { const feeProperty = blockTargetMapping[i]; if (feeProperty && mempoolFeeEstimates[feeProperty]) { feeByBlockTarget[i] = mempoolFeeEstimates[feeProperty]; @@ -469,12 +475,13 @@ export function calculateFees( mempoolFeeEstimates: MempoolFeeEstimates, esploraFeeEstimates: FeeByBlockTarget, bitcoindFeeEstimates: FeeByBlockTarget, + feeMinimum: number, ) { let feeByBlockTarget: FeeByBlockTarget = {}; // Get the mempool fee estimates. if (mempoolFeeEstimates) { - let estimates = extractMempoolFees(mempoolFeeEstimates); + let estimates = extractMempoolFees(mempoolFeeEstimates, MEMPOOL_DEPTH); estimates = processEstimates(estimates, true, true); addFeeEstimates(feeByBlockTarget, estimates); } @@ -491,12 +498,8 @@ export function calculateFees( addFeeEstimates(feeByBlockTarget, estimates); } - // Get the minimum fee. If the mempool fee estimates are not available, use a default value of FEE_MINIMUM sat/vbyte as a safety net. - const minFee = (mempoolFeeEstimates?.minimumFee ?? FEE_MINIMUM) * 1000; - log.info({ message: "Using minimum fee: {minFee}", minFee }); - // Filter the estimates to remove any that are lower than the desired minimum fee. - feeByBlockTarget = filterEstimates(feeByBlockTarget, minFee); + feeByBlockTarget = filterEstimates(feeByBlockTarget, feeMinimum); return feeByBlockTarget; } diff --git a/test/unit.test.ts b/test/unit.test.ts index 03c57b4..5c7e4f0 100644 --- a/test/unit.test.ts +++ b/test/unit.test.ts @@ -1,14 +1,89 @@ import { expect, test } from "bun:test"; -import { addFeeEstimates } from "../src/util"; +import { + addFeeEstimates, + filterEstimates, + extractMempoolFees, + calculateFees, +} from "../src/util"; +// Define test data +const mempoolFeeEstimates: MempoolFeeEstimates = { + fastestFee: 500, + halfHourFee: 400, + hourFee: 300, + economyFee: 200, + minimumFee: 100, +}; +const bitcoindFeeEstimates: FeeByBlockTarget = { + 1: 300000, + 10: 250000, + 20: 200000, +}; +const esploraFeeEstimates: FeeByBlockTarget = { + 10: 400000, + 20: 300000, + 30: 150000, +}; + +// Test addFeeEstimates function test("addFeeEstimates", () => { - const feeByBlockTarget: FeeByBlockTarget = { 1: 100, 2: 200, 3: 300 }; - const newEstimates: FeeByBlockTarget = { 4: 50, 5: 150, 6: 250 }; + const feeByBlockTarget: FeeByBlockTarget = { 1: 500, 2: 400, 3: 300 }; + const newEstimates: FeeByBlockTarget = { 4: 320, 5: 300, 6: 250 }; addFeeEstimates(feeByBlockTarget, newEstimates); - expect(feeByBlockTarget[4]).toEqual(50); + expect(feeByBlockTarget[1]).toEqual(500); + expect(feeByBlockTarget[2]).toEqual(400); + expect(feeByBlockTarget[3]).toEqual(300); + expect(feeByBlockTarget[4]).toBeUndefined(); expect(feeByBlockTarget[5]).toBeUndefined(); - expect(feeByBlockTarget[6]).toBeUndefined(); + expect(feeByBlockTarget[6]).toEqual(250); expect(Object.keys(feeByBlockTarget).length).toEqual(4); }); + +// Test filterEstimates function +test("filterEstimates", () => { + const feeByBlockTarget: FeeByBlockTarget = { 1: 500, 2: 400, 3: 300 }; + const feeMinimum = 350; + + const result = filterEstimates(feeByBlockTarget, feeMinimum); + + expect(result[1]).toEqual(500); + expect(result[2]).toEqual(400); + expect(result[3]).toBeUndefined(); + expect(Object.keys(result).length).toEqual(2); +}); + +// Test extractMempoolFees function +test("extractMempoolFees", () => { + const depth = 3; + + const result: FeeByBlockTarget = extractMempoolFees( + mempoolFeeEstimates, + depth, + ); + + expect(result[1]).toEqual(500); + expect(result[3]).toEqual(400); + expect(result[6]).toBeUndefined(); +}); + +// Test calculateFees function +test("calculateFees", () => { + const result: FeeByBlockTarget = calculateFees( + mempoolFeeEstimates, + esploraFeeEstimates, + bitcoindFeeEstimates, + 20000, + ); + + expect(result[1]).toEqual(500000); + expect(result[2]).toBeUndefined(); + expect(result[3]).toEqual(400000); + expect(result[4]).toBeUndefined(); + expect(result[6]).toEqual(300000); + expect(result[10]).toEqual(250000); + expect(result[20]).toEqual(200000); + expect(result[30]).toBeUndefined(); + expect(Object.keys(result).length).toEqual(5); +});