Skip to content

Commit

Permalink
Fix : TxAnalyzer RBF calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
Legend101Zz committed Oct 17, 2024
1 parent fa292dc commit ee59d3f
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const transactionAnalyzerFixtures = {
fee: "327",
feeRate: "2.61",
recommendedStrategy: FeeBumpStrategy.NONE,
estimatedRBFFee: 454, // 327 + 1*125.25
estimatedRBFFee: 453, // 327 + 1*125.25
estimatedCPFPFee: 73,
inputSequences: [4294967293],
outputValues: [37114, 0],
Expand Down Expand Up @@ -85,7 +85,7 @@ export const transactionAnalyzerFixtures = {
fee: "482",
feeRate: "3.43",
recommendedStrategy: FeeBumpStrategy.CPFP,
estimatedRBFFee: 702.5, // 562 + 1*140.5 = 576.5(minimum RBF for bumping , 1 sats/vbyte incremental fee) , here 5(user defined) * 140.5 = 702.5 ... note our txAnalyzer gives 705 for this because of vsize rounding from bitcoin-js lib
estimatedRBFFee: 623, // 482 + 1*140.5 = 622.5(minimum RBF for bumping , 1 sats/vbyte incremental fee)
estimatedCPFPFee: 2303,
inputSequences: [4294967295],
outputValues: [16741, 525461],
Expand Down Expand Up @@ -130,7 +130,7 @@ export const transactionAnalyzerFixtures = {
fee: "2289",
feeRate: "7.02",
recommendedStrategy: FeeBumpStrategy.RBF,
estimatedRBFFee: 4894, // 15(target Rate) * 326.25
estimatedRBFFee: 2616, // 2289 + 1 * 326.25
estimatedCPFPFee: 14692,
inputSequences: [4294967293],
outputValues: [
Expand Down
59 changes: 14 additions & 45 deletions packages/caravan-fees/src/transactionAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,23 +265,6 @@ export class TransactionAnalyzer {
return this._targetFeeRate;
}

/**
* Get the estimated fee rate for Replace-by-Fee (RBF).
*
* This method calculates the effective fee rate for the RBF transaction
* based on the minimum RBF fee and the transaction's virtual size.
*
* It's important to note that this rate might be higher than the original
* user-specified target fee rate, as it needs to satisfy both BIP 125 rules
* and current network conditions for effective replacement.
*
* @returns {string} The estimated RBF fee rate in satoshis per vbyte.
* @see https://bitcoinops.org/en/topics/replace-by-fee/
*/
get rbfFeeRate(): string {
return new BigNumber(this.minimumRBFFee).dividedBy(this.vsize).toString();
}

/**
* Calculates and returns the fee rate required for a successful CPFP.
* @returns {string} The CPFP fee rate in satoshis per vbyte
Expand All @@ -301,24 +284,21 @@ export class TransactionAnalyzer {
/**
* Calculates the minimum total fee required for a valid RBF (Replace-By-Fee) replacement transaction.
*
* This method implements the current RBF rules as defined in BIP 125, while also
* considering the fee rate importance. It balances:
* 1. BIP 125 requirements (anti-DDoS measures)
* 2. Current miner preferences for fee rates over absolute fees
* 3. User-specified target fee rate
* This method determines the minimum fee needed to replace the current transaction
* using the RBF protocol, as defined in BIP 125. It considers two key factors:
* 1. The current transaction fee
* 2. The minimum required fee increase (incremental relay fee * transaction size)
*
* Key considerations:
* - BIP 125 Rule 4: Replacement must pay for its own bandwidth at minimum relay fee
* This rule doesn't explicitly consider fee rates, focusing on anti-DDoS protection.
* - Modern mining preferences favor higher fee rates over absolute fees.
*
* Approach Taken:
* 1. Calculate minimum fee based on BIP 125 rules
* 2. Calculate fee based on user-specified target fee rate
* 3. Use the higher of these two to ensure compliance and desired confirmation speed
* The calculation ensures that the new transaction meets the minimum fee increase
* required by the RBF rules, which is:
* minimum_fee = original_fee + (incremental_relay_fee * transaction_size)
*
*
* This method allows for effective fee bumping while adhering to current network rules,
* even if the user-specified target fee rate is lower than necessary to unstick the transaction.
*
* References:
* - BIP 125 (RBF): https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki
Expand All @@ -327,25 +307,14 @@ export class TransactionAnalyzer {
* - One-Shot Replace-By-Fee-Rate proposal: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2024-January/022298.html
*
* @returns {Satoshis} The minimum total fee required for the replacement transaction in satoshis.
* This is always at least the current fee plus the minimum required increase,
* but may be higher if the user-specified target fee rate demands it.
* This is always at least the current fee plus the minimum required increase.
* @note This getter does not consider the user's target fee rate. It's the responsibility
* of the RBF function to ensure that the new transaction's fee is the maximum of
* this minimum fee and the fee calculated using the user's target fee rate.
*/
get minimumRBFFee(): Satoshis {
// Calculate the minimum fee increase required by BIP 125 Rule 4
// This includes the original fee rate plus the incremental relay fee rate
const minReplacementFee = new BigNumber(this.feeRate)
.plus(this._incrementalRelayFeeRate)
.multipliedBy(this.vsize);

// Calculate the fee based on the user-specified target fee rate
// This addresses modern miner preferences for higher fee rates
const targetFeeBasedOnUserRate = new BigNumber(
this.targetFeeRate,
).multipliedBy(this.vsize);

// Return the maximum of the two calculations
// This ensures we meet both RBF rules and user's desired fee rate
return BigNumber.max(minReplacementFee, targetFeeBasedOnUserRate)
return new BigNumber(this.fee)
.plus(this._incrementalRelayFeeRate.multipliedBy(this.vsize))
.integerValue(BigNumber.ROUND_CEIL)
.toString();
}
Expand Down

0 comments on commit ee59d3f

Please sign in to comment.