opnet
Version:
The perfect library for building Bitcoin-based applications.
75 lines (74 loc) • 3.18 kB
JavaScript
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 = {
[]: 148 * 4,
[]: 91 * 4 + 107,
[]: 41 * 4 + 107,
[]: 41 * 4 + 65,
[]: 148 * 4,
[]: 41 * 4 + (1 + 73 + 1 + 33),
[]: 41 * 4 + 107,
[]: 41 * 4 + 253,
};
const OUTPUT_BYTES = {
[]: 34,
[]: 32,
[]: 31,
[]: 43,
[]: 34,
[]: 32,
[]: 43,
[]: 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);
}
}