@caravan/clients
Version:
A package for querying different bitcoin blockchain backends
269 lines (264 loc) • 9.61 kB
TypeScript
import { Network } from '@caravan/bitcoin';
interface UTXO {
txid: string;
vout: number;
value: number;
status: {
confirmed: boolean;
block_time: number;
};
}
interface Transaction {
txid: string;
vin: Input[];
vout: Output[];
size: number;
weight: number;
fee: number;
isSend: boolean;
amount: number;
block_time: number;
}
interface Input {
prevTxId: string;
vout: number;
sequence: number;
}
interface Output {
scriptPubkeyHex: string;
scriptPubkeyAddress: string;
value: number;
}
interface FeeRatePercentile {
avgHeight: number;
timestamp: number;
avgFee_0: number;
avgFee_10: number;
avgFee_25: number;
avgFee_50: number;
avgFee_75: number;
avgFee_90: number;
avgFee_100: number;
}
interface TransactionDetails {
txid: string;
version: number;
locktime: number;
vin: Array<{
txid: string;
vout: number;
sequence: number;
}>;
vout: Array<{
value: number;
scriptPubkey: string;
scriptPubkeyAddress?: string;
}>;
size: number;
vsize?: number;
weight: number;
fee: number;
status: {
confirmed: boolean;
blockHeight?: number;
blockHash?: string;
blockTime?: number;
};
isReceived?: boolean;
}
interface WalletTransactionDetails extends TransactionDetails {
amount?: number;
confirmations?: number;
category?: string;
address?: string;
abandoned?: boolean;
time?: number;
}
/**
* Interface for RPC response structure
*/
interface RPCResponse<T = unknown> {
result: T;
error?: {
code: number;
message: string;
};
id: number;
}
declare function bitcoindImportDescriptors({ url, auth, walletName, receive, change, rescan, }: {
url: string;
auth: {
username: string;
password: string;
};
walletName?: string;
receive: string;
change: string;
rescan: boolean;
}): Promise<RPCResponse<unknown>>;
declare enum ClientType {
PRIVATE = "private",
PUBLIC = "public",
MEMPOOL = "mempool",
BLOCKSTREAM = "blockstream"
}
declare enum PublicBitcoinProvider {
BLOCKSTREAM = "blockstream",
MEMPOOL = "mempool"
}
declare class ClientBase {
private readonly throttled;
readonly host: string;
constructor(throttled: boolean, host: string);
private throttle;
private Request;
Get(path: string): Promise<any>;
Post(path: string, data?: any): Promise<any>;
}
interface BitcoindClientConfig {
url: string;
username: string;
password: string;
walletName?: string;
}
interface BitcoindParams {
url: string;
auth: {
username: string;
password: string;
};
walletName?: string;
}
interface BlockchainClientParams {
type: ClientType;
provider?: PublicBitcoinProvider;
network?: Network;
throttled?: boolean;
client?: BitcoindClientConfig;
}
declare class BlockchainClient extends ClientBase {
readonly type: ClientType;
readonly provider?: PublicBitcoinProvider;
readonly network?: Network;
readonly bitcoindParams: BitcoindParams;
constructor({ type, provider, network, throttled, client, }: BlockchainClientParams);
getAddressUtxos(address: string): Promise<any>;
getAddressTransactions(address: string): Promise<Transaction[]>;
broadcastTransaction(rawTx: string): Promise<any>;
formatUtxo(utxo: UTXO): Promise<any>;
fetchAddressUtxos(address: string): Promise<any>;
getAddressStatus(address: string): Promise<any>;
getFeeEstimate(blocks?: number): Promise<any>;
getBlockFeeRatePercentileHistory(): Promise<FeeRatePercentile[]>;
getTransactionHex(txid: string): Promise<any>;
/**
* Retrieves transaction history for one or more addresses (public clients only)
*
* This method is designed for public blockchain explorers (Mempool/Blockstream) that
* maintain address indexes, allowing efficient address-specific queries.
*
* Why this method is PUBLIC CLIENT ONLY:
* - Public APIs maintain address indexes for efficient lookups
* - Bitcoin Core doesn't support address-specific queries (see getWalletTransactionHistory)
* - Allows querying multiple addresses with Promise.all for efficiency
*
* For PRIVATE clients: Use getWalletTransactionHistory() which returns all wallet transactions
*
* @param address - Single address or array of addresses to query
* @param count - Number of transactions to return per address (1-100)
* @param skip - Number of transactions to skip for pagination
* @returns Combined array of transactions sorted by time (newest first)
* @throws Error if called on private client
*
* @example
* // Single address
* const txs = await client.getAddressTransactionHistory("bc1q...");
*
* // Multiple addresses
* const txs = await client.getAddressTransactionHistory(["bc1q...", "bc1p..."]);
*
* @see getWalletTransactionHistory - For private clients
*/
getAddressTransactionHistory(address: string | string[], count?: number, skip?: number): Promise<TransactionDetails[]>;
/**
* Retrieves transaction history for a Bitcoin Core wallet (private client only)
*
* This method returns only "send" (spent) transactions from the wallet. This design
* decision was made after extensive discussion about Bitcoin Core's limitations:
*
* 1. Bitcoin Core doesn't maintain an address index for performance/privacy reasons
* 2. The `listtransactions` RPC returns ALL wallet transactions with no address filtering
* 3. Filtering by address after fetching would be O(n*m) complexity for multiple addresses
*
* Why this method is PRIVATE CLIENT ONLY:
* - Public APIs (Mempool/Blockstream) support direct address querying
* - Bitcoin Core requires different approach due to lack of address indexing
* - This inconsistency is intentional to optimize for each client type's capabilities
*
* Why only "send" transactions:
* - Unspent "receive" transactions are already available via fetchAddressUtxos()
* - Avoids duplication of data that's accessible through UTXO methods
* - Focuses on spent transactions which are needed for transaction history
* - Coordinator can combine this with UTXO data for complete history
*
* For PUBLIC clients: Use getAddressTransactionHistory() which supports address filtering
*
* @param count - Number of transactions to return (1-1000)
* @param skip - Number of transactions to skip for pagination
* @param includeWatchOnly - Include watch-only addresses in results
* @returns Array of spent transactions from the wallet
* @throws Error if called on public client or if wallet name is missing
*
* @example
* // For private client - get last 100 spent transactions
* const spentTxs = await client.getWalletTransactionHistory(100);
*
* // For public client - use getAddressTransactionHistory instead
* const addressTxs = await client.getAddressTransactionHistory(address);
*
* @see getAddressTransactionHistory - For public clients
* @see fetchAddressUtxos - For unspent transactions
*/
getWalletTransactionHistory(count?: number, skip?: number, includeWatchOnly?: boolean): Promise<WalletTransactionDetails[]>;
/**
* Gets detailed information about a wallet transaction including fee information
*
* This method is specifically for transactions that are tracked by the wallet,
* and provides fee information that isn't available in the general getTransaction
* method. This is especially useful for private nodes where fee information is
* critical for UI display.
*
* @see https://developer.bitcoin.org/reference/rpc/gettransaction.html
*
* @param txid - Transaction ID to retrieve
* @returns Normalized transaction details with fee information
*/
getWalletTransaction(txid: string): Promise<TransactionDetails>;
getTransaction(txid: string, forceRawTx?: boolean): Promise<TransactionDetails>;
importDescriptors({ receive, change, rescan, }: {
receive: string;
change: string;
rescan: boolean;
}): Promise<object>;
getWalletInfo(): Promise<RPCResponse<unknown>>;
/**
* Retrieves the fee information for a pending (incoming) transaction .
*
* Standard methods like `getTransaction` do not provide fee details for transactions
* where the user is the recipient. However, this information is required for
* fee bumping strategies like CPFP (Child Pays For Parent).
*
* This method :
* - For private nodes: Uses `getmempoolentry` to fetch fee data from the node's mempool
* - For public APIs: Uses mempool.space transaction endpoint to get fee information
* - Returns null if the transaction is not pending (not in mempool)
*
* @see https://developer.bitcoin.org/reference/rpc/getmempoolentry.html?highlight=getmempoolentry
* @see https://mempool.space/docs/api/rest#get-transaction
*
* @param txid - Transaction ID to get fees
* @returns Tx fees in satoshis, or null if transaction is not pending
*/
getFeesForPendingTransaction(txid: string): Promise<string | null>;
}
export { BlockchainClient, ClientType, type FeeRatePercentile, PublicBitcoinProvider, type Transaction, type TransactionDetails, type UTXO, type WalletTransactionDetails, bitcoindImportDescriptors };