OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-wallet-lib / blockchain-api.cjs

167 lines · javascript ref:
/**
 * Blockchain API - Phase 6.3
 *
 * Wrapper around WDK blockchain queries.
 * Provides unified interface for querying UTXOs, transactions, and fees.
 */

/**
 * Query UTXOs for a Bitcoin address
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @param {string} address - Bitcoin address (tb1q... for testnet)
 * @returns {Array} Array of UTXO objects
 */
async function getUTXOsForAddress(btcWallet, address) {
  try {
    const utxos = await btcWallet.getUTXOs(address)

    // Normalize UTXO format
    return utxos.map(utxo => ({
      txid: utxo.txid,
      vout: utxo.vout,
      address: address,
      value: utxo.value, // satoshis
      scriptPubKey: utxo.scriptPubKey || null,
      confirmations: utxo.confirmations || 0,
      blockHeight: utxo.height || null
    }))
  } catch (err) {
    console.error(`Error fetching UTXOs for ${address}:`, err.message)
    return []
  }
}

/**
 * Query UTXOs for multiple addresses
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @param {Array} addresses - Array of address strings
 * @returns {Array} Combined array of UTXOs from all addresses
 */
async function getUTXOsForAddresses(btcWallet, addresses) {
  const allUTXOs = []

  for (const address of addresses) {
    const utxos = await getUTXOsForAddress(btcWallet, address)
    allUTXOs.push(...utxos)
  }

  return allUTXOs
}

/**
 * Get current fee rates from network
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @returns {Object} Fee rates in sat/vbyte
 */
async function getFeeRates(btcWallet) {
  try {
    const rates = await btcWallet.getFeeRates()

    return {
      low: rates.low || 1,
      medium: rates.medium || 5,
      high: rates.high || 10
    }
  } catch (err) {
    console.error('Error fetching fee rates:', err.message)

    // Return default rates on error
    return {
      low: 1,
      medium: 5,
      high: 10
    }
  }
}

/**
 * Get transaction details from blockchain
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @param {string} txid - Transaction ID
 * @returns {Object|null} Transaction details or null if not found
 */
async function getTransaction(btcWallet, txid) {
  try {
    const tx = await btcWallet.getTransaction(txid)

    return {
      txid: tx.txid,
      confirmations: tx.confirmations || 0,
      blockHeight: tx.blockHeight || null,
      blockHash: tx.blockHash || null,
      timestamp: tx.timestamp || null,
      inputs: tx.inputs || [],
      outputs: tx.outputs || [],
      fee: tx.fee || null
    }
  } catch (err) {
    console.error(`Error fetching transaction ${txid}:`, err.message)
    return null
  }
}

/**
 * Get balance for a single address (direct query)
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @param {string} address - Bitcoin address
 * @returns {number} Balance in satoshis
 */
async function getAddressBalance(btcWallet, address) {
  try {
    const balance = await btcWallet.getBalance(address)
    return balance || 0
  } catch (err) {
    console.error(`Error fetching balance for ${address}:`, err.message)
    return 0
  }
}

/**
 * Broadcast transaction to network
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @param {string} txHex - Signed transaction hex
 * @returns {Object} Broadcast result
 */
async function broadcastTransaction(btcWallet, txHex) {
  try {
    const result = await btcWallet.broadcast(txHex)

    return {
      success: true,
      txid: result.txid,
      message: 'Transaction broadcasted successfully'
    }
  } catch (err) {
    return {
      success: false,
      error: err.message,
      message: 'Failed to broadcast transaction'
    }
  }
}

/**
 * Check if blockchain API is reachable
 * @param {Object} btcWallet - WDK Bitcoin wallet instance
 * @returns {boolean} True if API is reachable
 */
async function checkConnection(btcWallet) {
  try {
    // Try to get fee rates as a connectivity check
    await btcWallet.getFeeRates()
    return true
  } catch (err) {
    return false
  }
}

module.exports = {
  getUTXOsForAddress,
  getUTXOsForAddresses,
  getFeeRates,
  getTransaction,
  getAddressBalance,
  broadcastTransaction,
  checkConnection
}