Creating a Custom Transaction Fee Model
Default Fee Model
/**
* Represents the interface for a transaction fee model.
* This interface defines a standard method for computing a fee when given a transaction.
*
* @interface
* @property {function} computeFee - A function that takes a Transaction object and returns a BigNumber representing the number of satoshis the transaction should cost.
*/
export default interface FeeModel {
computeFee: (transaction: Transaction) => Promise<number>
}
/**
* Represents the "satoshis per kilobyte" transaction fee model.
*/
export default class SatoshisPerKilobyte implements FeeModel {
/**
* @property
* Denotes the number of satoshis paid per kilobyte of transaction size.
*/
value: number
/**
* Constructs an instance of the sat/kb fee model.
*
* @param {number} value - The number of satoshis per kilobyte to charge as a fee.
*/
constructor(value: number) {
this.value = value
}
/**
* Computes the fee for a given transaction.
*
* @param tx The transaction for which a fee is to be computed.
* @returns The fee in satoshis for the transaction, as a number.
*/
async computeFee(tx: Transaction): Promise<number> {
const getVarIntSize = (i: number): number => {
if (i > 2 ** 32) {
return 9
} else if (i > 2 ** 16) {
return 5
} else if (i > 253) {
return 3
} else {
return 1
}
}
// Compute the (potentially estimated) size of the transaction
let size = 4 // version
size += getVarIntSize(tx.inputs.length) // number of inputs
for (let i = 0; i < tx.inputs.length; i++) {
const input = tx.inputs[i]
size += 40 // txid, output index, sequence number
let scriptLength: number
if (typeof input.unlockingScript === 'object') {
scriptLength = input.unlockingScript.toBinary().length
} else if (typeof input.unlockingScriptTemplate === 'object') {
scriptLength = await input.unlockingScriptTemplate.estimateLength(tx, i)
} else {
throw new Error('All inputs must have an unlocking script or an unlocking script template for sat/kb fee computation.')
}
size += getVarIntSize(scriptLength) // unlocking script length
size += scriptLength // unlocking script
}
size += getVarIntSize(tx.outputs.length) // number of outputs
for (const out of tx.outputs) {
size += 8 // satoshis
const length = out.lockingScript.toBinary().length
size += getVarIntSize(length) // script length
size += length // script
}
size += 4 // lock time
// We'll use Math.ceil to ensure the miners get the extra satoshi.
const fee = Math.ceil((size / 1000) * this.value)
return fee
}
}Making Adjustments
PreviousUsing Type 42 Key Derivation for Bitcoin Wallet ManagementNextBuilding a Pulse Block Headers Client
Last updated
