Source: utils/keyUtil.js

const bitcoin = require("bitcoinjs-lib");
const { BIP32Factory } = require("bip32");
const bip39 = require("bip39");
const ecc = require("tiny-secp256k1");
const { encryptPrivateKey } = require("./encryptionUtil");

// Define the network for testnet
const network = bitcoin.networks.testnet;

// Initialize bip32 with tiny-secp256k1
const bip32 = BIP32Factory(ecc);

/**
 * Generates a new HD wallet using BIP84 standard including the seed.
 * Uses BIP39 for mnemonic generation and BIP32 for key derivation.
 *
 * @function generateHDSegWitWalletWithSeed
 * @return {Object} An object containing the master public key, encrypted master private key,
 *                  encrypted seed, and derivation path.
 */
const generateHDSegWitWalletWithSeed = () => {
  const mnemonic = bip39.generateMnemonic();
  const seed = bip39.mnemonicToSeedSync(mnemonic);
  const root = bip32.fromSeed(seed, network);
  const masterPublicKey = root.neutered().toBase58();
  const encryptedMasterPrivateKey = encryptPrivateKey(root.toBase58());
  const encryptedSeed = encryptPrivateKey(mnemonic);
  const derivationPath = "m/84'/1'/0'"; // For reference (P2WSH) BIP84 Testnet Hardened Derivation Path

  return {
    masterPublicKey,
    encryptedMasterPrivateKey,
    encryptedSeed,
    derivationPath,
  };
};

/**
 * Generate a child address from the master key using a specified derivation path.
 * This function supports generating P2WPKH addresses.
 *
 * @function generateChildAddress
 * @param {string} masterPublicKey - The master public key of the HD wallet.
 * @param {number} childIndex - The index of the child key to generate.
 * @return {Object} An object containing the child address and derivation path.
 */
const generateChildAddress = (masterPublicKey, childIndex) => {
  const node = bip32.fromBase58(masterPublicKey, network);

  // Adjust the derivation path to include the child index for non-hardened derivation
  const derivationPath = `m/84/1/0/0/${childIndex}`; // BIP84 for P2WPKH (SegWit) derivation path for Testnet
  const child = node.derivePath(derivationPath);

  // Create a P2WPKH address
  const { address } = bitcoin.payments.p2wpkh({
    pubkey: child.publicKey,
    network,
  });

  return { address, path: derivationPath };
};

module.exports = {
  generateHDSegWitWalletWithSeed,
  generateChildAddress,
};