Skip to content

Commit

Permalink
feat(sdk): add mempool client (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsimao authored Oct 17, 2024
1 parent 2150f15 commit 52a7920
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 1 deletion.
2 changes: 1 addition & 1 deletion sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gobob/bob-sdk",
"version": "3.0.0",
"version": "3.0.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './ordinals';
export * from './helpers';
export * from './wallet';
export * from './gateway';
export * from './mempool';
102 changes: 102 additions & 0 deletions sdk/src/mempool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Base path for the mainnet Memopool API.
* @default "https://btc-mainnet.gobob.xyz"
*/
export const MAINNET_MEMPOOL_BASE_PATH = 'https://mempool.space/api/v1/';
/**
* Base path for the testnet Memopool API.
* @default "https://btc-testnet.gobob.xyz"
*/
export const TESTNET_MEMPOOL_BASE_PATH = 'https://mempool.space/testnet4/api/v1';
/**
* Base path for the regtest Memopool API.
* @default "http://localhost:3003"
*/
export const REGTEST_MEMPOOL_BASE_PATH = 'http://localhost:3003';

/**
* @ignore
*/
export type MempoolRecomendedFee = {
fastestFee: number;
halfHourFee: number;
hourFee: number;
economyFee: number;
minimumFee: number;
};

export class MempoolClient {
private basePath: string;

/**
* Create an instance of the `MempoolPool` with the specified network or URL.
* If the `networkOrUrl` parameter is omitted, it defaults to "mainnet."
*
* @param networkOrUrl The Bitcoin network (e.g., "mainnet," "testnet," "regtest")
*
* @returns An instance of the `MempoolPool` configured for the specified network or URL.
*
* @example
* const BITCOIN_NETWORK = "regtest";
* const mempoolClient = new MempoolPool(BITCOIN_NETWORK);
*
* @example
* // Create a client for the mainnet using the default URL.
* const mempoolClientMainnet = new MempoolPool();
*/
constructor(networkOrUrl: string = 'mainnet') {
switch (networkOrUrl) {
case 'mainnet':
this.basePath = MAINNET_MEMPOOL_BASE_PATH;
break;
case 'testnet':
this.basePath = TESTNET_MEMPOOL_BASE_PATH;
break;
case 'regtest':
this.basePath = REGTEST_MEMPOOL_BASE_PATH;
break;
default:
this.basePath = networkOrUrl;
}
}

/**
* Get the recommended Bitcoin transaction fee rates from the Mempool API.
*
* This method returns the fee estimates in satoshis per virtual byte (sat/vB)
* for different confirmation targets, including:
*
* - `fastestFee`: The fee rate for transactions that are likely to be included
* in the next block (fastest possible confirmation).
* - `halfHourFee`: The fee rate for transactions that are likely to be confirmed
* within 30 minutes.
* - `hourFee`: The fee rate for transactions that are likely to be confirmed
* within an hour.
* - `economyFee`: The fee rate for transactions that are likely to be confirmed
* in a longer period (low priority).
* - `minimumFee`: The lowest fee rate that is still accepted by miners.
*
* @returns {Promise<MempoolRecomendedFee>} A promise that resolves to an object containing
* the recommended fees for various confirmation times.
*
* @example
* const mempoolClient = new MempoolClient();
* mempoolClient.getRecommendedFees()
* .then(fees => console.log(fees))
* .catch(error => console.error('Failed to fetch fees:', error));
*/
async getRecommendedFees(): Promise<MempoolRecomendedFee> {
return this.getJson<MempoolRecomendedFee>(`${this.basePath}/fees/recommended`);
}

/**
* @ignore
*/
private async getJson<T>(url: string): Promise<T> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(response.statusText);
}
return (await response.json()) as Promise<T>;
}
}
41 changes: 41 additions & 0 deletions sdk/test/mempool.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { MempoolClient } from '../src/mempool';

const MOCKS = {
fees: {
recommended: {
fastestFee: 100,
halfHourFee: 80,
hourFee: 60,
economyFee: 40,
minimumFee: 10,
},
},
};

describe('Mempool Tests', () => {
const client = new MempoolClient();

beforeEach(() => {
// Mock the fetch API only for URLs including /fees/recommended
global.fetch = vi.fn((url) => {
if (url.includes('/fees/recommended')) {
return Promise.resolve({
ok: true,
json: () => Promise.resolve(MOCKS.fees.recommended),
} as Response);
}
return Promise.reject(new Error('Unexpected URL'));
});
});

afterEach(() => {
vi.clearAllMocks();
});

it('should get recommended fee', async () => {
const fees = await client.getRecommendedFees();

expect(fees).toEqual(MOCKS.fees.recommended);
});
});

0 comments on commit 52a7920

Please sign in to comment.