Source: utils/feeUtil.js

const { getAPI } = require("./apiUtil");
const bitcoin = require("bitcoinjs-lib");

// Configuration for BlockCypher API
const apiBaseUrl = process.env.BLOCKCYPHER_BASE_URL;

/**
 * @fileoverview Utility functions for handling transaction fees in Satoshi Showdown.
 * Includes functionality for fetching current network fee rates and estimating
 * transaction fees based on transaction details.
 *
 * @module utils/feeUtil
 * @requires utils/apiUtil - For making API requests.
 * @requires bitcoinjs-lib - For transaction calculations.
 */

/**
 * Fetches the current Bitcoin network fee rates (high, medium, low) from BlockCypher.
 * @async
 * @return {Promise<{highFeePerByte: number, mediumFeePerByte: number, lowFeePerByte: number}>}
 *          An object containing high, medium, and low fee rates in satoshis per byte.
 * @throws {Error} If the request to the BlockCypher API fails.
 */
const getCurrentFeeRates = async () => {
  try {
    const url = `${apiBaseUrl}`;
    const data = await getAPI(url);

    return {
      highFeePerByte: Math.ceil(data.high_fee_per_kb / 1024),
      mediumFeePerByte: Math.ceil(data.medium_fee_per_kb / 1024),
      lowFeePerByte: Math.ceil(data.low_fee_per_kb / 1024),
    };
  } catch (error) {
    throw new Error(`Error fetching current fee rates: ${error.message}`);
  }
};

/**
 * Estimates the transaction fee in satoshis based on the number of inputs, outputs, and the fee rate.
 * Uses the formula for virtual size (vSize) to calculate the fee more accurately for SegWit transactions.
 *
 * @param {number} numInputs - Number of transaction inputs.
 * @param {number} numOutputs - Number of transaction outputs.
 * @param {number} feeRate - Fee rate in satoshis per byte.
 * @return {number} Estimated transaction fee in satoshis.
 */
const estimateTransactionFee = (numInputs, numOutputs, feeRate) => {
  // Create a dummy transaction to estimate its size
  const tx = new bitcoin.Transaction();

  // Dummy hash for inputs (32-byte zero buffer)
  const dummyHash = Buffer.alloc(32); // 32-byte buffer of zeros

  for (let i = 0; i < numInputs; i++) {
    // Add dummy inputs using a buffer of 32 bytes of zeros
    tx.addInput(dummyHash, 0); // Zero for index
  }

  for (let i = 0; i < numOutputs; i++) {
    // Add dummy outputs (script and value are irrelevant for size calculation)
    // Using a 22-byte buffer as a placeholder for the script
    tx.addOutput(Buffer.alloc(22), 0); // Zero for amount
  }

  // Calculate the virtual size (vSize) of the transaction
  const vSize = tx.virtualSize();

  console.log("vSize:", vSize);

  // Estimate fee = vSize * feeRate
  return Math.ceil(vSize * feeRate);
};

/**
 * Adjusts the transaction amount to account for the transaction fee.
 * This function ensures that the fee is deducted from the total amount, avoiding leaving dust in the wallet.
 *
 * @param {number} amount - Original transaction amount in satoshis.
 * @param {number} fee - Transaction fee in satoshis.
 * @return {number} Adjusted amount after deducting the fee.
 */
const adjustAmountForFee = (amount, fee) => {
  return Math.max(amount - fee, 0);
};

module.exports = {
  getCurrentFeeRates,
  estimateTransactionFee,
  adjustAmountForFee,
};