UNPKG

@nawab_kibria/bitcoin-lib

Version:

A comprehensive Bitcoin HD wallet library with BIP84, BIP44, BIP49 support, mnemonic generation and restoration

318 lines (317 loc) 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.BitcoinWallet = void 0; const bitcoin = __importStar(require("bitcoinjs-lib")); const ecpair_1 = require("ecpair"); const ecc = __importStar(require("tiny-secp256k1")); const bip39 = __importStar(require("bip39")); const bip32_1 = require("bip32"); const bip84_1 = require("../utils/bip84"); const ECPair = (0, ecpair_1.ECPairFactory)(ecc); const bip32 = (0, bip32_1.BIP32Factory)(ecc); class BitcoinWallet { constructor(options = {}) { this.network = options.network || bitcoin.networks.regtest; this.addressCount = options.addressCount || 1; // Generate or use provided mnemonic this.mnemonic = options.mnemonic || bip39.generateMnemonic(128); // Validate mnemonic if (!bip39.validateMnemonic(this.mnemonic)) { throw new Error('Invalid mnemonic provided'); } // Generate seed and root key this.seed = Buffer.from(bip39.mnemonicToSeedSync(this.mnemonic)); this.root = bip32.fromSeed(this.seed, this.network); } /** * Set the network dynamically */ setNetwork(network) { this.network = network; // Regenerate root key with new network this.root = bip32.fromSeed(this.seed, this.network); } /** * Get current network */ getNetwork() { return this.network; } /** * Get wallet keys including mnemonic, xpub, xpriv, and first P2WPKH address * Now includes zpub/vpub for BIP84 Native SegWit */ getWalletKeys(network) { const targetNetwork = network || this.network; const coinType = (0, bip84_1.getCoinType)(targetNetwork); const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const account = rootForNetwork.derivePath(`m/84'/${coinType}'/0'`); const firstAddressNode = account.derive(0).derive(0); // Generate first P2WPKH address const { address } = bitcoin.payments.p2wpkh({ pubkey: Buffer.from(firstAddressNode.publicKey), network: targetNetwork, }); const xpub = account.neutered().toBase58(); const xpriv = account.toBase58(); // Get BIP84 formatted extended keys const bip84Keys = (0, bip84_1.getBip84ExtendedKeys)(this.seed, targetNetwork); return { mnemonic: this.mnemonic, xpub, xpriv, firstAddress: address, zpub: bip84Keys.zpub, zprv: bip84Keys.zprv }; } /** * Get BIP84-specific extended keys (zpub/vpub format) */ getBip84Keys(network) { const targetNetwork = network || this.network; return (0, bip84_1.getBip84ExtendedKeys)(this.seed, targetNetwork); } /** * Generate P2WPKH (Native SegWit) addresses - BIP84 */ generateNativeSegwitAddresses(count = this.addressCount, network) { const targetNetwork = network || this.network; const coinType = (0, bip84_1.getCoinType)(targetNetwork); const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const account = rootForNetwork.derivePath(`m/84'/${coinType}'/0'`); const addresses = []; for (let i = 0; i < count; i++) { const child = account.derive(0).derive(i); const derivationPath = (0, bip84_1.getDerivationPath)(84, targetNetwork, 0, 0, i); const { address } = bitcoin.payments.p2wpkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }); addresses.push({ address: address, publicKey: Buffer.from(child.publicKey).toString('hex'), privateKey: Buffer.from(child.privateKey).toString('hex'), derivationPath }); } return addresses; } /** * Generate P2PKH (Legacy) addresses - BIP44 */ generateLegacyAddresses(count = this.addressCount, network) { const targetNetwork = network || this.network; const coinType = (0, bip84_1.getCoinType)(targetNetwork); const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const account = rootForNetwork.derivePath(`m/44'/${coinType}'/0'`); const addresses = []; for (let i = 0; i < count; i++) { const child = account.derive(0).derive(i); const derivationPath = (0, bip84_1.getDerivationPath)(44, targetNetwork, 0, 0, i); const { address } = bitcoin.payments.p2pkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }); addresses.push({ address: address, publicKey: Buffer.from(child.publicKey).toString('hex'), privateKey: Buffer.from(child.privateKey).toString('hex'), derivationPath }); } return addresses; } /** * Generate P2SH-P2WPKH (SegWit) addresses - BIP49 */ generateSegwitAddresses(count = this.addressCount, network) { const targetNetwork = network || this.network; const coinType = (0, bip84_1.getCoinType)(targetNetwork); const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const account = rootForNetwork.derivePath(`m/49'/${coinType}'/0'`); const addresses = []; for (let i = 0; i < count; i++) { const child = account.derive(0).derive(i); const derivationPath = (0, bip84_1.getDerivationPath)(49, targetNetwork, 0, 0, i); const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }), network: targetNetwork, }); addresses.push({ address: address, publicKey: Buffer.from(child.publicKey).toString('hex'), privateKey: Buffer.from(child.privateKey).toString('hex'), derivationPath }); } return addresses; } /** * Get address by specific derivation path */ getAddressByPath(path, addressType = 'native-segwit', network) { const targetNetwork = network || this.network; const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const child = rootForNetwork.derivePath(path); let address; switch (addressType) { case 'legacy': const legacyPayment = bitcoin.payments.p2pkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }); address = legacyPayment.address; break; case 'segwit': const segwitPayment = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }), network: targetNetwork, }); address = segwitPayment.address; break; default: // native-segwit const nativeSegwitPayment = bitcoin.payments.p2wpkh({ pubkey: Buffer.from(child.publicKey), network: targetNetwork, }); address = nativeSegwitPayment.address; break; } return { address, publicKey: Buffer.from(child.publicKey).toString('hex'), privateKey: Buffer.from(child.privateKey).toString('hex'), derivationPath: path }; } /** * Generate addresses for multiple networks at once */ generateMultiNetworkAddresses(addressCount = 1) { return { mainnet: this.generateNativeSegwitAddresses(addressCount, bitcoin.networks.bitcoin), testnet: this.generateNativeSegwitAddresses(addressCount, bitcoin.networks.testnet), regtest: this.generateNativeSegwitAddresses(addressCount, bitcoin.networks.regtest) }; } /** * Get wallet keys for all networks */ getAllNetworkKeys() { return { mainnet: this.getWalletKeys(bitcoin.networks.bitcoin), testnet: this.getWalletKeys(bitcoin.networks.testnet), regtest: this.getWalletKeys(bitcoin.networks.regtest) }; } /** * Get the mnemonic phrase */ getMnemonic() { return this.mnemonic; } /** * Get the seed */ getSeed() { return this.seed; } /** * Get root extended private key */ getRootXPriv(network) { const targetNetwork = network || this.network; const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; return rootForNetwork.toBase58(); } /** * Get root extended public key */ getRootXPub(network) { const targetNetwork = network || this.network; const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; return rootForNetwork.neutered().toBase58(); } /** * Get root extended keys in BIP84 format (zpub/zprv for mainnet, vpub/vprv for testnet) */ getRootBip84Keys(network) { const targetNetwork = network || this.network; // Create custom network config with BIP84 version bytes const bip84Network = Object.assign(Object.assign({}, targetNetwork), { bip32: { public: targetNetwork === bitcoin.networks.bitcoin ? 0x04b24746 : 0x045f1cf6, // zpub/vpub private: targetNetwork === bitcoin.networks.bitcoin ? 0x04b2430c : 0x045f18bc // zprv/vprv } }); const root = bip32.fromSeed(this.seed, bip84Network); return { zpub: root.neutered().toBase58(), zprv: root.toBase58() }; } /** * Get account extended keys for specific purpose (44, 49, 84, or 86) */ getAccountKeys(purpose, network) { const targetNetwork = network || this.network; const coinType = (0, bip84_1.getCoinType)(targetNetwork); const rootForNetwork = network ? bip32.fromSeed(this.seed, targetNetwork) : this.root; const account = rootForNetwork.derivePath(`m/${purpose}'/${coinType}'/0'`); return { xpriv: account.toBase58(), xpub: account.neutered().toBase58() }; } /** * Static method to restore wallet from mnemonic */ static fromMnemonic(mnemonic, network) { return new BitcoinWallet({ mnemonic, network }); } /** * Static method to generate new wallet */ static generate(network) { return new BitcoinWallet({ network }); } } exports.BitcoinWallet = BitcoinWallet;