UNPKG

@nawab_kibria/bitcoin-lib

Version:

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

310 lines (309 loc) 12.2 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; }; })(); var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertToBip84Format = convertToBip84Format; exports.getBip84ExtendedKeys = getBip84ExtendedKeys; exports.getCoinType = getCoinType; exports.getDerivationPath = getDerivationPath; exports.importAndDerive = importAndDerive; exports.importAndDeriveBatch = importAndDeriveBatch; exports.importExtendedKey = importExtendedKey; exports.quickDerive = quickDerive; const bitcoin = __importStar(require("bitcoinjs-lib")); const bip32_1 = require("bip32"); const ecpair_1 = require("ecpair"); const ecc = __importStar(require("tiny-secp256k1")); const bs58check = require("bs58check"); const bip32 = (0, bip32_1.BIP32Factory)(ecc); const ECPair = (0, ecpair_1.ECPairFactory)(ecc); // Initialize ECC library for bitcoinjs-lib Taproot operations bitcoin.initEccLib(ecc); /** * Convert standard extended key to BIP84-specific format with proper version bytes */ function convertToBip84Format(extendedKey, network, isPrivate = false) { // Version bytes for different key formats const versions = { // Mainnet xpub: 0x0488b21e, xprv: 0x0488ade4, // Legacy ypub: 0x049d7cb2, yprv: 0x049d7878, // SegWit zpub: 0x04b24746, zprv: 0x04b2430c, // Native SegWit // Testnet tpub: 0x043587cf, tprv: 0x04358394, // Legacy upub: 0x044a5262, uprv: 0x044a4e28, // SegWit vpub: 0x045f1cf6, vprv: 0x045f18bc, // Native SegWit }; try { // Decode the extended key to get the raw data const decoded = bs58check.decode(extendedKey); // Determine target version bytes based on network and key type let targetVersion; if (network === bitcoin.networks.bitcoin) { targetVersion = isPrivate ? versions.zprv : versions.zpub; } else { // For testnet/regtest targetVersion = isPrivate ? versions.vprv : versions.vpub; } // Create new buffer with target version bytes const newBuffer = Buffer.alloc(decoded.length); // Write the new version bytes (4 bytes, big endian) newBuffer.writeUInt32BE(targetVersion, 0); // Copy the rest of the data (depth, fingerprint, child number, chain code, key data) Buffer.from(decoded).copy(newBuffer, 4, 4); // Encode with base58check return bs58check.encode(newBuffer); } catch (error) { // Fallback to simple prefix replacement if proper conversion fails if (network === bitcoin.networks.bitcoin) { if (isPrivate) { return extendedKey.replace(/^xprv/, 'zprv'); } else { return extendedKey.replace(/^xpub/, 'zpub'); } } else { // For testnet/regtest if (isPrivate) { return extendedKey.replace(/^tprv/, 'vprv'); } else { return extendedKey.replace(/^tpub/, 'vpub'); } } } } /** * Get BIP84-specific extended keys for a given seed and network * This generates proper BIP84 extended keys with correct version bytes */ function getBip84ExtendedKeys(seed, network) { // Create custom network config with BIP84 version bytes const bip84Network = Object.assign(Object.assign({}, network), { bip32: { public: network === bitcoin.networks.bitcoin ? 0x04b24746 : 0x045f1cf6, // zpub/vpub private: network === bitcoin.networks.bitcoin ? 0x04b2430c : 0x045f18bc // zprv/vprv } }); const root = bip32.fromSeed(seed, bip84Network); const coinType = network === bitcoin.networks.bitcoin ? 0 : 1; const account = root.derivePath(`m/84'/${coinType}'/0'`); return { zpub: account.neutered().toBase58(), zprv: account.toBase58() }; } /** * Get coin type for a given network (BIP44 standard) */ function getCoinType(network) { return network === bitcoin.networks.bitcoin ? 0 : 1; } /** * Get derivation path for different BIP standards */ function getDerivationPath(purpose, network, account = 0, change = 0, addressIndex = 0) { const coinType = getCoinType(network); return `m/${purpose}'/${coinType}'/${account}'/${change}/${addressIndex}`; } /** * Import and derive address and keys for any index from mnemonic or root key * This is a flexible utility for wallet recovery and address generation */ function importAndDerive(options) { const { mnemonic, rootKey, purpose, network = bitcoin.networks.bitcoin, account = 0, change = 0, index, addressType } = options; // Validation if (!mnemonic && !rootKey) { throw new Error('Either mnemonic or rootKey must be provided'); } if (mnemonic && rootKey) { throw new Error('Provide either mnemonic or rootKey, not both'); } // Determine address type from purpose if not provided const finalAddressType = addressType || (() => { switch (purpose) { case 44: return 'legacy'; case 49: return 'segwit'; case 84: return 'native-segwit'; case 86: return 'native-segwit'; // Default to native-segwit for BIP86 default: throw new Error(`Unsupported purpose: ${purpose}`); } })(); // Create derivation path const coinType = getCoinType(network); const derivationPath = `m/${purpose}'/${coinType}'/${account}'/${change}/${index}`; let root; try { if (mnemonic) { // Import from mnemonic const bip39 = require('bip39'); if (!bip39.validateMnemonic(mnemonic)) { throw new Error('Invalid mnemonic provided'); } const seed = Buffer.from(bip39.mnemonicToSeedSync(mnemonic)); root = bip32.fromSeed(seed, network); } else { // Import from root key root = bip32.fromBase58(rootKey, network); } // Derive the specific address // If the root key is already at account level or deeper, adjust the derivation path let child; try { child = root.derivePath(derivationPath); } catch (error) { // If full derivation fails, try relative path from the imported key if (error instanceof Error && error.message.includes('master')) { // Imported key might be account-level, try relative derivation const relativePath = `${change}/${index}`; child = root.derivePath(relativePath); } else { throw error; } } const privateKey = Buffer.from(child.privateKey); const publicKey = Buffer.from(child.publicKey); // Generate address based on type let address; let internalKey; let signingKey; switch (finalAddressType) { case 'legacy': const legacyPayment = bitcoin.payments.p2pkh({ pubkey: publicKey, network, }); address = legacyPayment.address; break; case 'segwit': const segwitPayment = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }), network, }); address = segwitPayment.address; break; case 'native-segwit': const nativeSegwitPayment = bitcoin.payments.p2wpkh({ pubkey: publicKey, network, }); address = nativeSegwitPayment.address; break; default: throw new Error(`Unsupported address type: ${finalAddressType}`); } return { address, publicKey: publicKey.toString('hex'), privateKey: privateKey.toString('hex'), derivationPath, addressType: finalAddressType, internalKey, signingKey }; } catch (error) { throw new Error(`Failed to import and derive: ${error}`); } } /** * Batch import and derive multiple addresses from mnemonic or root key */ function importAndDeriveBatch(options) { const { startIndex = 0, count } = options, baseOptions = __rest(options, ["startIndex", "count"]); const results = []; for (let i = 0; i < count; i++) { const index = startIndex + i; const result = importAndDerive(Object.assign(Object.assign({}, baseOptions), { index })); results.push(Object.assign(Object.assign({}, result), { index })); } return results; } /** * Import from extended key and get account-level information */ function importExtendedKey(extendedKey, network) { try { const targetNetwork = network || bitcoin.networks.bitcoin; const node = bip32.fromBase58(extendedKey, targetNetwork); return { isPrivate: !!node.privateKey, depth: node.depth, parentFingerprint: node.parentFingerprint, childNumber: node.index, chainCode: node.chainCode.toString('hex'), key: node.privateKey ? node.privateKey.toString('hex') : node.publicKey.toString('hex'), xpub: node.neutered().toBase58(), xprv: node.privateKey ? node.toBase58() : undefined, network: targetNetwork }; } catch (error) { throw new Error(`Failed to import extended key: ${error}`); } } /** * Quick address lookup - derive single address from any source */ function quickDerive(source, // mnemonic or extended key purpose, index, network) { const targetNetwork = network || bitcoin.networks.bitcoin; // Auto-detect if source is mnemonic or extended key const isMnemonic = source.split(' ').length >= 12; // Assume mnemonic if 12+ words const result = importAndDerive(Object.assign(Object.assign({}, (isMnemonic ? { mnemonic: source } : { rootKey: source })), { purpose, index, network: targetNetwork })); return { address: result.address, derivationPath: result.derivationPath, addressType: result.addressType }; }