UNPKG

opnet

Version:

The perfect library for building Bitcoin-based applications.

75 lines (74 loc) 3.18 kB
import { AddressTypes, AddressVerificator } from '@btc-vision/transaction'; export class TransactionHelper { static estimateMiningCost(utxos, extraOutputs, opReturnLen, network, feeRate) { const vBytes = this.estimateVBytes(utxos, extraOutputs, opReturnLen, network); return BigInt(Math.ceil(vBytes * feeRate)); } static varIntLen(n) { return n < 0xfd ? 1 : n <= 0xffff ? 3 : n <= 0xffffffff ? 5 : 9; } static estimateVBytes(utxos, extraOutputs, scriptLength, network) { const INPUT_WU = { [AddressTypes.P2PKH]: 148 * 4, [AddressTypes.P2SH_OR_P2SH_P2WPKH]: 91 * 4 + 107, [AddressTypes.P2WPKH]: 41 * 4 + 107, [AddressTypes.P2TR]: 41 * 4 + 65, [AddressTypes.P2PK]: 148 * 4, [AddressTypes.P2WSH]: 41 * 4 + (1 + 73 + 1 + 33), [AddressTypes.P2OP]: 41 * 4 + 107, [AddressTypes.P2WDA]: 41 * 4 + 253, }; const OUTPUT_BYTES = { [AddressTypes.P2PKH]: 34, [AddressTypes.P2SH_OR_P2SH_P2WPKH]: 32, [AddressTypes.P2WPKH]: 31, [AddressTypes.P2TR]: 43, [AddressTypes.P2PK]: 34, [AddressTypes.P2OP]: 32, [AddressTypes.P2WSH]: 43, [AddressTypes.P2WDA]: 43, }; const ins = utxos.length ? utxos : new Array(3).fill(null); let weight = 0; weight += 8 * 4; const usesWitness = utxos.length === 0 || utxos.some((u) => { const t = AddressVerificator.detectAddressType(u?.scriptPubKey?.address ?? '', network); return (t === AddressTypes.P2WPKH || t === AddressTypes.P2SH_OR_P2SH_P2WPKH || t === AddressTypes.P2TR || t === AddressTypes.P2OP || t === AddressTypes.P2WSH); }); if (usesWitness) weight += 2 * 4; weight += this.varIntLen(ins.length) * 4; weight += this.varIntLen(extraOutputs.length) * 4; for (const u of ins) { const t = utxos.length === 0 ? AddressTypes.P2TR : (AddressVerificator.detectAddressType(u?.scriptPubKey?.address ?? '', network) ?? AddressTypes.P2PKH); weight += INPUT_WU[t] ?? 110 * 4; } for (const o of extraOutputs) { if ('address' in o) { const t = AddressVerificator.detectAddressType(o.address, network) ?? AddressTypes.P2PKH; weight += (OUTPUT_BYTES[t] ?? 40) * 4; } else if ('script' in o) { const scriptLen = o.script.length; const bytes = 8 + this.varIntLen(scriptLen) + scriptLen; weight += bytes * 4; } else { weight += 34 * 4; } } const witnessBytes = 1 + 3 * (this.varIntLen(32) + 32); weight += witnessBytes; const stackItemScript = this.varIntLen(scriptLength) + scriptLength; const controlBlock = 1 + 33; weight += stackItemScript + controlBlock; return Math.ceil(weight / 4); } }