All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.fr.acinq.lightning.blockchain.fee.FeeEstimator.kt Maven / Gradle / Ivy

package fr.acinq.lightning.blockchain.fee

import fr.acinq.bitcoin.Satoshi
import fr.acinq.lightning.blockchain.Feerates
import fr.acinq.lightning.utils.sat

interface FeeEstimator {
    fun getFeerate(target: Int): FeeratePerKw
}

/**
 * Preferences regarding on-chain feerates that will be applied to various transactions.
 *
 * @param fundingFeerate feerate used for funding transactions, including splices (typically configured by the user, based on their preference).
 * @param mutualCloseFeerate feerate used in mutual close scenarios (typically configured by the user, based on their preference).
 * @param claimMainFeerate feerate used to claim our main output when a channel is force-closed (typically configured by the user, based on their preference).
 * @param fastFeerate feerate used to claim outputs quickly to avoid loss of funds: this one should not be set by the user (we should look at current on-chain fees).
 */
data class OnChainFeerates(val fundingFeerate: FeeratePerKw, val mutualCloseFeerate: FeeratePerKw, val claimMainFeerate: FeeratePerKw, val fastFeerate: FeeratePerKw) {
    constructor(feerates: Feerates) : this(
        fundingFeerate = FeeratePerKw(feerates.medium),
        mutualCloseFeerate = FeeratePerKw(feerates.medium),
        claimMainFeerate = FeeratePerKw(feerates.medium),
        fastFeerate = FeeratePerKw(feerates.fast),
    )
}

data class FeerateTolerance(val ratioLow: Double, val ratioHigh: Double)

data class OnChainFeeConf(val closeOnOfflineMismatch: Boolean, val updateFeeMinDiffRatio: Double, val feerateTolerance: FeerateTolerance)

/** Fee rate in satoshi-per-bytes. */
data class FeeratePerByte(val feerate: Satoshi) {
    constructor(feeratePerKw: FeeratePerKw) : this(FeeratePerKB(feeratePerKw).feerate / 1000)

    override fun toString(): String = "$feerate/byte"
}

/** Fee rate in satoshi-per-kilo-bytes (1 kB = 1000 bytes). */
data class FeeratePerKB(val feerate: Satoshi) : Comparable {
    constructor(feeratePerByte: FeeratePerByte) : this(feeratePerByte.feerate * 1000)
    constructor(feeratePerKw: FeeratePerKw) : this(feeratePerKw.feerate * 4)

    override fun compareTo(other: FeeratePerKB): Int = feerate.compareTo(other.feerate)
    fun max(other: FeeratePerKB): FeeratePerKB = if (this > other) this else other
    fun min(other: FeeratePerKB): FeeratePerKB = if (this < other) this else other
    fun toLong(): Long = feerate.toLong()

    override fun toString(): String = "$feerate/kB"
}

/** Fee rate in satoshi-per-kilo-weight. */
data class FeeratePerKw(val feerate: Satoshi) : Comparable {
    constructor(feeratePerKB: FeeratePerKB) : this(MinimumFeeratePerKw.feerate.max(feeratePerKB.feerate / 4))
    constructor(feeratePerByte: FeeratePerByte) : this(FeeratePerKB(feeratePerByte))

    override fun compareTo(other: FeeratePerKw): Int = feerate.compareTo(other.feerate)
    fun max(other: FeeratePerKw): FeeratePerKw = if (this > other) this else other
    fun min(other: FeeratePerKw): FeeratePerKw = if (this < other) this else other
    operator fun plus(other: FeeratePerKw): FeeratePerKw = FeeratePerKw(feerate + other.feerate)
    operator fun times(d: Double): FeeratePerKw = FeeratePerKw(feerate * d)
    operator fun times(l: Long): FeeratePerKw = FeeratePerKw(feerate * l)
    operator fun div(l: Long): FeeratePerKw = FeeratePerKw(feerate / l)
    fun toLong(): Long = feerate.toLong()

    override fun toString(): String = "$feerate/kw"

    companion object {
        /**
         * Minimum relay fee rate in satoshi per kilo-vbyte (taken from Bitcoin Core).
         * Note that Bitcoin Core uses a *virtual size* and not the actual size in bytes: see [[MinimumFeeratePerKw]] below.
         */
        const val MinimumRelayFeeRate = 1000

        /**
         * Why 253 and not 250 since feerate-per-kw should be feerate-per-kvb / 4 and the minimum relay fee rate is
         * 1000 satoshi/kvb (see [[MinimumRelayFeeRate]])?
         *
         * Because Bitcoin Core uses neither the actual tx size in bytes nor the tx weight to check fees, but a "virtual size"
         * which is (3 + weight) / 4.
         * So we want:
         * fee > 1000 * virtual size
         * feerate-per-kw * weight > 1000 * (3 + weight / 4)
         * feerate-per-kw > 250 + 3000 / (4 * weight)
         *
         * With a conservative minimum weight of 400, assuming the result of the division may be rounded up and using strict
         * inequality to err on the side of safety, we get:
         * feerate-per-kw > 252
         * hence feerate-per-kw >= 253
         */
        val MinimumFeeratePerKw = FeeratePerKw(253.sat)

        /**
         * Since we're using anchor outputs, we don't need to constantly adjust the feerate of the commitment tx to match current on-chain feerates.
         * We can instead set it to a low-enough value, that still ensures the transaction will relay through the bitcoin network, and then use CPFP to make it confirm.
         * TODO: we should regularly get fee estimations from various sources to ensure this default value remains relay-able, and otherwise raise it dynamically.
         */
        val CommitmentFeerate = FeeratePerKw(FeeratePerByte(20.sat))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy