Back to blog list

Published on Wed, Feb 21, 2024 by jp1ac4

Implementing RBF functionality in Liana

An overview of how we implemented RBF functionality in Liana and some of the problems we faced

Blog image cover
Bump the fee of an unconfirmed transaction or cancel it

Replace-By-Fee (RBF) functionality has been available in Liana since the release of v4 in December 2023.

As mentioned in its accompanying blog post, this release coincided with a period of high transaction fees and so the option to use RBF was very welcome to those Liana users (including members of the Wizardsardine team!) with transactions stuck in the mempool waiting for confirmation.

In Liana, RBF can be used to replace an unconfirmed transaction in two ways:

  • bump its fee to speed up confirmation
  • cancel it by replacing it with another transaction that sends the funds back to the user’s own wallet

This blog post gives an overview of RBF functionality in Liana and some of the challenges encountered during its implementation, as well as plans for future development.

Automated coin selection

We started working towards RBF in June 2023, but soon realised that we should first add automated coin selection (#51).

At the time, Liana only supported manual coin selection when creating a new spend, but automated coin selection would be required for both of the RBF use cases we were planning:

  • bumping a transaction’s fee might require additional coins to pay the higher fee
  • when cancelling a transaction, the replacement transaction only needs at least one of the coins from the transaction being replaced

Fortunately, the BDK team were working on a new implementation of their coin selection algorithm, which would conveniently be in its own zero-dependency crate (bitcoindevkit/bdk#924).

This crate uses a branch-and-bound algorithm to search for different coin selections at the target feerate, choosing the selection that minimises the value of a given metric.

For both RBF and non-RBF uses of automated coin selection, Liana uses a metric, also part of the coin selection crate, that minimises the total transaction fee paid, including the estimated future fee of spending any change output created by this transaction.

Automated coin selection was added to Liana in #560 and also released in v4. As a follow-up task, we plan to adapt the metric used for selection to favour those coins near expiration of their recovery timelocks, thereby reducing the number of coins that need to be “refreshed” manually by the user.

Minimum fee and replacement transaction size

There are various conditions that must be met by a replacement transaction in order to use RBF, as listed here. One challenge we faced was how to use the coin selection crate with rule 4, which states:

“The additional fees (difference between absolute fee paid by the replacement transaction and the sum paid by the original transactions) pays for the replacement transaction’s bandwidth at or above the rate set by the node’s incremental relay feerate. For example, if the incremental relay feerate is 1 satoshi/vB and the replacement transaction is 500 virtual bytes total, then the replacement pays a fee at least 500 satoshis higher than the sum of the original transactions.”

The trouble was that the coin selection API only allowed to set a minimum fee a priori, while this rule imposes a mininum fee based on the size of the replacement transaction itself.

As a short-term workaround, we simply use the coin selection algorithm repeatedly with an increasing minimum fee until this condition is satisfied. This is not ideal, however, as it requires the selection algorithm to be run multiple times and may result in a slight fee overpayment.

The coin selection API has since been updated in bitcoindevkit/coin-select#19 so that the algorithm only needs to be run once when creating a replacement transaction, which will be added to Liana in a future release.

Mandatory change outputs

As described above, for our second RBF use case, a transaction can be “cancelled” by replacing it with another that sends the funds back to the user’s own wallet.

This is implemented as a “sweep” transaction to a change address in the user’s wallet, with the input coins chosen in such a way as to minimise the fee paid while sasisfying all RBF conditions.

For this purpose, the replacement transaction must have change, but the coin selection algorithm could return a selection with no change, which in this case would mean a transaction with no outputs at all.

We therefore made a modification in #832 to the metric we were using for coin selection so that, if required, it would ignore selections that did not give any change. This modification is sub-optimal since the algorithm may still search branches that only give solutions without change, and alternative approaches have been discussed in bitcoindevkit/coin-select#17.

Further development

As already mentioned above, there are various follow-up tasks planned.

An important one, given the nature of Liana, is to allow the use of RBF on transactions broadcast from another wallet (#854), which might be required in the case of a threshold multisig wallet, for example. Currently, the user can only use RBF on a transaction created in their own wallet.

Adding RBF functionality to Liana was an important step, especially as high-fee environments become more common, and we will continue looking for ways to enhance and extend it.