UNPKG

bitcoin-tx-lib

Version:

A Typescript library for building and signing Bitcoin transactions

153 lines 5.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HDTransaction = void 0; const hdtxbase_1 = require("./base/hdtxbase"); const utils_1 = require("./utils"); /** * HDTransaction represents a Bitcoin transaction using hierarchical deterministic keys. * Inherits from HDTransactionBase and provides high-level utilities such as fee calculation, * weight estimation, and raw hex retrieval. */ class HDTransaction extends hdtxbase_1.HDTransactionBase { /** * Constructs a new HDTransaction. * @param options Optional transaction parameters (version, locktime, fee, etc.). */ constructor(options) { super(options); } /** * Returns the transaction ID (txid) as a hex string. * It is the double SHA-256 hash of the raw transaction (excluding witness data), * reversed in byte order. * * @throws Error if the transaction is not signed. * @returns The txid in hex string format. */ getTxid() { if (!this.cachedata.get("txidraw")) this.sign(); let hexTransaction = this.cachedata.get("txidraw"); if (!hexTransaction) throw new Error("Transaction not signed, please sign the transactio"); let txid = (0, utils_1.hash256)(hexTransaction).reverse(); return (0, utils_1.bytesToHex)(txid); } /** * Signs the transaction and stores both the full raw transaction and * the stripped version used to calculate the txid. */ sign() { this.cachedata.set("txraw", this.build()); this.cachedata.set("txidraw", this.build()); } /** * Determines if the transaction contains any SegWit inputs. * @returns True if the transaction has at least one SegWit input. */ isSegwit() { return super.isSegwit(); } /** * Calculates the total weight of the transaction as defined in BIP 141. * Weight = (non-witness bytes * 4) + witness bytes. * * @throws Error if the transaction is not signed. * @returns The transaction weight. */ weight() { if (!this.cachedata.get("txraw")) this.sign(); // witness marker and flag * 1 let witnessMK = 0; // 2 bytes of marker and flag 0x00+0x01 = 2 bytes * 1 if (this.isSegwit()) witnessMK = 2; let hexTransaction = this.cachedata.get("txraw"); let witnessInputs = this.inputs.filter(this.isSegwitInput); // witness size * 1 let witnessSize = witnessInputs.reduce((sum, input) => { let witness = this.buildWitness(input); return sum + witness.length; }, 0); // discount the size of the witness fields and multiply by 4 let transactionSize = hexTransaction.length; transactionSize = (transactionSize - (witnessSize + witnessMK)) * 4; transactionSize += (witnessSize + witnessMK); // * 1 return Math.ceil(transactionSize); } /** * Calculates the virtual size (vBytes) of the transaction, defined as weight / 4. * * @throws Error if the transaction is not signed. * @returns The virtual size of the transaction in vBytes. */ vBytes() { return Math.ceil(this.weight() / 4); } /** * Resolves and deducts the transaction fee from the specified output(s). * * Fee deduction strategy: * - If one output: subtracts total fee from that output. * - If `whoPayTheFee` is "everyone": splits the fee among all outputs equally. * - If `whoPayTheFee` is an address: subtracts full fee from that address. * * @throws Error if the transaction is not signed. */ resolveFee() { var _a, _b; if (!this.cachedata.get("txraw")) this.sign(); let satoshis = Math.ceil(this.vBytes() * ((_a = this.fee) !== null && _a !== void 0 ? _a : 1)); if (this.outputs.length == 1) { this.outputs[0].amount -= satoshis; return; } if (this.whoPayTheFee === "everyone") { satoshis = Math.ceil(this.vBytes() * ((_b = this.fee) !== null && _b !== void 0 ? _b : 1) / this.outputs.length); this.outputs.forEach(out => out.amount -= satoshis); } for (let i = 0; i < this.outputs.length; i++) { if (this.outputs[i].address == this.whoPayTheFee) { this.outputs[i].amount -= satoshis; break; } } } /** * Calculates the fee in satoshis based on vBytes and configured fee rate. * * @returns Total transaction fee in satoshis. */ getFeeSats() { var _a; if (this.whoPayTheFee && this.fee) this.resolveFee(); const feeSats = Math.ceil(this.vBytes() * ((_a = this.fee) !== null && _a !== void 0 ? _a : 1)); return feeSats; } /** * Returns the raw transaction as a hex-encoded string. * * @throws Error if the transaction is not signed. * @returns Raw transaction in hex format. */ getRawHex() { if (!this.cachedata.get("txraw")) this.sign(); return (0, utils_1.bytesToHex)(this.cachedata.get("txraw")); } /** * Returns the raw transaction as a Uint8Array. * * @throws Error if the transaction is not signed. * @returns Raw transaction as bytes. */ getRawBytes() { if (!this.cachedata.get("txraw")) this.sign(); return this.cachedata.get("txraw"); } } exports.HDTransaction = HDTransaction; //# sourceMappingURL=hdtransaction.js.map