What changed, and why it matters
This commit is a pure code cleanup: it replaces nested constructor calls like FeeratePerKw(FeeratePerByte(x)) with new helper methods like x.perKw. The math and behavior are unchanged; only the syntax is shorter and more readable.
No security action needed; treat as routine refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces convenience methods (perByte, perKB, perKw) on the fee-rate case classes in FeeProvider.scala and mechanically refactors all call sites across the codebase to use them. The conversion factors (1 kB = 1000 bytes, 1 kW = 250 bytes, minimum 253 sat/kw) remain identical. No logic, validation, or security behavior was modified.
Changed components
eclair-core fee conversion helpersAPI handlers for channel and control endpointsNodeParams configuration parsingBitcoinCoreClient transaction fundingChannel commitment and dust-exposure logicTest suitesInspect captured patch +65 / −62
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
index fa41c23..005d44e 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala
@@ -245,7 +245,7 @@ class EclairImpl(val appKit: Kit) extends Eclair with Logging with SpendFromChan
fundingAmount = fundingAmount,
channelType_opt = channelType_opt,
pushAmount_opt = pushAmount_opt,
- fundingTxFeerate_opt = fundingFeerate_opt.map(FeeratePerKw(_)),
+ fundingTxFeerate_opt = fundingFeerate_opt.map(_.perKw),
fundingTxFeeBudget_opt = Some(fundingFeeBudget),
requestFunding_opt = None,
channelFlags_opt = announceChannel_opt.map(announceChannel => ChannelFlags(announceChannel = announceChannel)),
@@ -441,7 +441,7 @@ class EclairImpl(val appKit: Kit) extends Eclair with Logging with SpendFromChan
if (blocks < 3) appKit.nodeParams.currentBitcoinCoreFeerates.fast
else if (blocks > 6) appKit.nodeParams.currentBitcoinCoreFeerates.slow
else appKit.nodeParams.currentBitcoinCoreFeerates.medium
- case Right(feeratePerByte) => FeeratePerKw(feeratePerByte)
+ case Right(feeratePerByte) => feeratePerByte.perKw
}
appKit.wallet match {
case w: BitcoinCoreClient =>
@@ -455,7 +455,7 @@ class EclairImpl(val appKit: Kit) extends Eclair with Logging with SpendFromChan
override def cpfpBumpFees(targetFeeratePerByte: FeeratePerByte, outpoints: Set[OutPoint]): Future[TxId] = {
appKit.wallet match {
- case w: BitcoinCoreClient => w.cpfp(outpoints, FeeratePerKw(targetFeeratePerByte)).map(_.txid)
+ case w: BitcoinCoreClient => w.cpfp(outpoints, targetFeeratePerByte.perKw).map(_.txid)
case _ => Future.failed(new IllegalArgumentException("this call is only available with a bitcoin core backend"))
}
}
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
index 4e835c5..b583332 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala
@@ -609,7 +609,7 @@ object NodeParams extends Logging {
),
onChainFeeConf = OnChainFeeConf(
feeTargets = feeTargets,
- maxClosingFeerate = FeeratePerKw(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.max-closing-feerate")))),
+ maxClosingFeerate = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.max-closing-feerate"))).perKw,
safeUtxosThreshold = config.getInt("on-chain-fees.safe-utxos-threshold"),
spendAnchorWithoutHtlcs = config.getBoolean("on-chain-fees.spend-anchor-without-htlcs"),
anchorWithoutHtlcsMaxFee = Satoshi(config.getLong("on-chain-fees.anchor-without-htlcs-max-fee-satoshis")),
@@ -618,7 +618,7 @@ object NodeParams extends Logging {
defaultFeerateTolerance = FeerateTolerance(
config.getDouble("on-chain-fees.feerate-tolerance.ratio-low"),
config.getDouble("on-chain-fees.feerate-tolerance.ratio-high"),
- FeeratePerKw(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.feerate-tolerance.anchor-output-max-commit-feerate")))),
+ FeeratePerByte(Satoshi(config.getLong("on-chain-fees.feerate-tolerance.anchor-output-max-commit-feerate"))).perKw,
DustTolerance(
Satoshi(config.getLong("on-chain-fees.feerate-tolerance.dust-tolerance.max-exposure-satoshis")),
config.getBoolean("on-chain-fees.feerate-tolerance.dust-tolerance.close-on-update-fee-overflow")
@@ -629,7 +629,7 @@ object NodeParams extends Logging {
val tolerance = FeerateTolerance(
e.getDouble("feerate-tolerance.ratio-low"),
e.getDouble("feerate-tolerance.ratio-high"),
- FeeratePerKw(FeeratePerByte(Satoshi(e.getLong("feerate-tolerance.anchor-output-max-commit-feerate")))),
+ FeeratePerByte(Satoshi(e.getLong("feerate-tolerance.anchor-output-max-commit-feerate"))).perKw,
DustTolerance(
Satoshi(e.getLong("feerate-tolerance.dust-tolerance.max-exposure-satoshis")),
e.getBoolean("feerate-tolerance.dust-tolerance.close-on-update-fee-overflow")
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
index e0336c3..a11d8c1 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
@@ -237,11 +237,11 @@ class Setup(val datadir: File,
defaultFeerates = {
val confDefaultFeerates = FeeratesPerKB(
- minimum = FeeratePerKB(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.minimum")))),
- slow = FeeratePerKB(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.slow")))),
- medium = FeeratePerKB(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.medium")))),
- fast = FeeratePerKB(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.fast")))),
- fastest = FeeratePerKB(FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.fastest")))),
+ minimum = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.minimum"))).perKB,
+ slow = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.slow"))).perKB,
+ medium = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.medium"))).perKB,
+ fast = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.fast"))).perKB,
+ fastest = FeeratePerByte(Satoshi(config.getLong("on-chain-fees.default-feerates.fastest"))).perKB,
)
feeratesPerKw.set(FeeratesPerKw(confDefaultFeerates))
confDefaultFeerates
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala
index 5dfecb6..d48600e 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinCoreClient.scala
@@ -263,7 +263,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
def fundTransaction(tx: Transaction, feeRate: FeeratePerKw, replaceable: Boolean = true, changePosition: Option[Int] = None, externalInputsWeight: Map[OutPoint, Long] = Map.empty, minInputConfirmations_opt: Option[Int] = None, feeBudget_opt: Option[Satoshi] = None)(implicit ec: ExecutionContext): Future[FundTransactionResponse] = {
val options = FundTransactionOptions(
- feeRate = BigDecimal(FeeratePerKB(feeRate).toLong).bigDecimal.scaleByPowerOfTen(-8),
+ feeRate = BigDecimal(feeRate.perKB.toLong).bigDecimal.scaleByPowerOfTen(-8),
replaceable = replaceable,
// We must either *always* lock inputs selected for funding or *never* lock them, otherwise locking wouldn't work
// at all, as the following scenario highlights:
@@ -357,7 +357,7 @@ class BitcoinCoreClient(val rpcClient: BitcoinJsonRPCClient, val lockUtxos: Bool
for {
// TODO: we should check that mempoolMinFee is not dangerously high
- feerate <- mempoolMinFee().map(minFee => FeeratePerKw(minFee).max(targetFeerate))
+ feerate <- mempoolMinFee().map(minFee => minFee.perKw.max(targetFeerate))
// we ask bitcoin core to add inputs to the funding tx, and use the specified change address
FundTransactionResponse(tx, fee, _) <- fundTransaction(partialFundingTx, feerate, feeBudget_opt = feeBudget_opt)
lockedUtxos = tx.txIn.map(_.outPoint)
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/FeeProvider.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/FeeProvider.scala
index 2123ef8..0ef8e8a 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/FeeProvider.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/fee/FeeProvider.scala
@@ -32,19 +32,21 @@ case object CannotRetrieveFeerates extends RuntimeException("cannot retrieve fee
/** Fee rate in satoshi-per-bytes. */
case class FeeratePerByte(feerate: Satoshi) {
+ def perKw: FeeratePerKw = FeeratePerKw(this)
def perKB: FeeratePerKB = FeeratePerKB(this)
override def toString: String = s"$feerate/byte"
}
object FeeratePerByte {
- def apply(feeratePerKB: FeeratePerKB): FeeratePerByte = FeeratePerByte(feeratePerKB.feerate / 1000)
- def apply(feeratePerKw: FeeratePerKw): FeeratePerByte = FeeratePerByte(FeeratePerKB(feeratePerKw))
+ private[fee] def apply(feeratePerKB: FeeratePerKB): FeeratePerByte = FeeratePerByte(feeratePerKB.feerate / 1000)
+ private[fee] def apply(feeratePerKw: FeeratePerKw): FeeratePerByte = FeeratePerByte(FeeratePerKB(feeratePerKw))
}
/** Fee rate in satoshi-per-kilo-bytes (1 kB = 1000 bytes). */
case class FeeratePerKB(feerate: Satoshi) extends Ordered[FeeratePerKB] {
// @formatter:off
def perByte: FeeratePerByte = FeeratePerByte(this)
+ def perKw: FeeratePerKw = FeeratePerKw(this)
override def compare(that: FeeratePerKB): Int = feerate.compare(that.feerate)
def max(other: FeeratePerKB): FeeratePerKB = if (this > other) this else other
def min(other: FeeratePerKB): FeeratePerKB = if (this < other) this else other
@@ -55,8 +57,8 @@ case class FeeratePerKB(feerate: Satoshi) extends Ordered[FeeratePerKB] {
object FeeratePerKB {
// @formatter:off
- def apply(feeratePerByte: FeeratePerByte): FeeratePerKB = FeeratePerKB(feeratePerByte.feerate * 1000)
- def apply(feeratePerKw: FeeratePerKw): FeeratePerKB = FeeratePerKB(feeratePerKw.feerate * 4)
+ private[fee] def apply(feeratePerByte: FeeratePerByte): FeeratePerKB = FeeratePerKB(feeratePerByte.feerate * 1000)
+ private[fee] def apply(feeratePerKw: FeeratePerKw): FeeratePerKB = FeeratePerKB(feeratePerKw.feerate * 4)
// @formatter:on
}
@@ -64,6 +66,7 @@ object FeeratePerKB {
case class FeeratePerKw(feerate: Satoshi) extends Ordered[FeeratePerKw] {
// @formatter:off
def perByte: FeeratePerByte = FeeratePerByte(this)
+ def perKB: FeeratePerKB = FeeratePerKB(this)
override def compare(that: FeeratePerKw): Int = feerate.compare(that.feerate)
def max(other: FeeratePerKw): FeeratePerKw = if (this > other) this else other
def min(other: FeeratePerKw): FeeratePerKw = if (this < other) this else other
@@ -104,8 +107,8 @@ object FeeratePerKw {
val MinimumFeeratePerKw = FeeratePerKw(253 sat)
// @formatter:off
- def apply(feeratePerKB: FeeratePerKB): FeeratePerKw = MinimumFeeratePerKw.max(FeeratePerKw(feeratePerKB.feerate / 4))
- def apply(feeratePerByte: FeeratePerByte): FeeratePerKw = FeeratePerKw(FeeratePerKB(feeratePerByte))
+ private[fee] def apply(feeratePerKB: FeeratePerKB): FeeratePerKw = MinimumFeeratePerKw.max(FeeratePerKw(feeratePerKB.feerate / 4))
+ private[fee] def apply(feeratePerByte: FeeratePerByte): FeeratePerKw = FeeratePerKw(FeeratePerKB(feeratePerByte))
// @formatter:on
}
@@ -140,7 +143,7 @@ object FeeratesPerKw {
fastest = FeeratePerKw(feerates.fastest))
/** Used in tests */
- def single(feeratePerKw: FeeratePerKw, networkMinFee: FeeratePerKw = FeeratePerKw(FeeratePerByte(1 sat))): FeeratesPerKw = FeeratesPerKw(
+ def single(feeratePerKw: FeeratePerKw, networkMinFee: FeeratePerKw = FeeratePerByte(1 sat).perKw): FeeratesPerKw = FeeratesPerKw(
minimum = networkMinFee,
slow = feeratePerKw,
medium = feeratePerKw,
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
index a18906b..7200127 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala
@@ -1061,7 +1061,7 @@ case class Commitments(channelParams: ChannelParams,
active.map(_.canSendFee(cmd.feeratePerKw, channelParams, changes1, feeConf))
.collectFirst { case Left(f) => Left(f) }
.getOrElse {
- Metrics.LocalFeeratePerByte.withTag(Tags.CommitmentFormat, active.head.commitmentFormat.toString).record(FeeratePerByte(cmd.feeratePerKw).feerate.toLong)
+ Metrics.LocalFeeratePerByte.withTag(Tags.CommitmentFormat, active.head.commitmentFormat.toString).record(cmd.feeratePerKw.perByte.feerate.toLong)
Right(copy(changes = changes1), fee)
}
}
@@ -1080,7 +1080,7 @@ case class Commitments(channelParams: ChannelParams,
active.map(_.canReceiveFee(fee.feeratePerKw, channelParams, changes1, feerates, feeConf))
.collectFirst { case Left(f) => Left(f) }
.getOrElse {
- Metrics.RemoteFeeratePerByte.withTag(Tags.CommitmentFormat, active.head.commitmentFormat.toString).record(FeeratePerByte(fee.feeratePerKw).feerate.toLong)
+ Metrics.RemoteFeeratePerByte.withTag(Tags.CommitmentFormat, active.head.commitmentFormat.toString).record(fee.feeratePerKw.perByte.feerate.toLong)
Right(copy(changes = changes1))
}
}
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/DustExposure.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/DustExposure.scala
index 2279e87..a8af347 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/DustExposure.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/DustExposure.scala
@@ -36,7 +36,7 @@ object DustExposure {
* However, this cannot fully protect us if the feerate increases too much (in which case we may have to force-close).
*/
def feerateForDustExposure(currentFeerate: FeeratePerKw): FeeratePerKw = {
- (currentFeerate * 1.25).max(currentFeerate + FeeratePerKw(FeeratePerByte(10 sat)))
+ (currentFeerate * 1.25).max(currentFeerate + FeeratePerByte(10 sat).perKw)
}
/** Test whether the given HTLC contributes to our dust exposure with the default dust feerate calculation. */
diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala
index f1e071e..8b7fb20 100644
--- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala
+++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Helpers.scala
@@ -1246,7 +1246,7 @@ object Helpers {
*/
private def claimIncomingHtlcOutputs(commitKeys: RemoteCommitmentKeys, commitTx: Transaction, outputs: Seq[CommitmentOutput], commitment: FullCommitment, remoteCommit: RemoteCommit, finalScriptPubKey: ByteVector)(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[ClaimHtlcSuccessTx]) = {
// The feerate will be set by the publisher actor based on the HTLC expiry, we don't care which feerate is used here.
- val feerate = FeeratePerKw(FeeratePerByte(1 sat))
+ val feerate = FeeratePerByte(1 sat).perKw
// We collect all the preimages available.
val preimages = (commitment.changes.localChanges.all ++ commitment.changes.remoteChanges.all).collect {
case u: UpdateFulfillHtlc => Crypto.sha256(u.paymentPreimage) -> u.paymentPreimage
@@ -1292,7 +1292,7 @@ object Helpers {
*/
private def claimOutgoingHtlcOutputs(commitKeys: RemoteCommitmentKeys, commitTx: Transaction, outputs: Seq[CommitmentOutput], commitment: FullCommitment, remoteCommit: RemoteCommit, finalScriptPubKey: ByteVector)(implicit log: LoggingAdapter): (Map[OutPoint, Long], Seq[ClaimHtlcTimeoutTx]) = {
// The feerate will be set by the publisher actor based on the HTLC expiry, we don't care which feerate is used here.
- val feerate = FeeratePerKw(FeeratePerByte(1 sat))
+ val feerate = FeeratePerByte(1 sat).perKw
// Remember we are looking at the remote commitment so IN for them is really OUT for us and vice versa.
val outgoingHtlcs = remoteCommit.spec.htlcs.collect {
case IncomingHtlc(add: UpdateAddHtlc) =>
@@ -1312,7 +1312,7 @@ object Helpers {
def claimHtlcsWithPreimage(channelKeys: ChannelKeys, commitKeys: RemoteCommitmentKeys, remoteCommitPublished: RemoteCommitPublished, commitment: FullCommitment, remoteCommit: RemoteCommit, preimage: ByteVector32, finalScriptPubKey: ByteVector)(implicit log: LoggingAdapter): Seq[ClaimHtlcSuccessTx] = {
val outputs = makeRemoteCommitTxOutputs(channelKeys, commitKeys, commitment, remoteCommit)
// The feerate will be set by the publisher actor based on the HTLC expiry, we don't care which feerate is used here.
- val feerate = FeeratePerKw(FeeratePerByte(1 sat))
+ val feerate = FeeratePerByte(1 sat).perKw
remoteCommit.spec.htlcs.collect {
// Remember we are looking at the remote commitment so IN for them is really OUT for us and vice versa.
case OutgoingHtlc(add: UpdateAddHtlc) if add.paymentHash == Crypto.sha256(preimage) =>
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala
index e78d929..805f9f2 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/StartupSpec.scala
@@ -340,9 +340,9 @@ class StartupSpec extends AnyFunSuite {
)
val nodeParams = makeNodeParamsWithDefaults(perNodeConf.withFallback(defaultConf))
- assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f")) == FeerateTolerance(0.1, 15.0, FeeratePerKw(FeeratePerByte(15 sat)), DustTolerance(25_000 sat, closeOnUpdateFeeOverflow = true)))
- assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b")) == FeerateTolerance(0.75, 5.0, FeeratePerKw(FeeratePerByte(5 sat)), DustTolerance(40_000 sat, closeOnUpdateFeeOverflow = false)))
- assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7")) == FeerateTolerance(0.5, 10.0, FeeratePerKw(FeeratePerByte(10 sat)), DustTolerance(50_000 sat, closeOnUpdateFeeOverflow = false)))
+ assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f")) == FeerateTolerance(0.1, 15.0, FeeratePerByte(15 sat).perKw, DustTolerance(25_000 sat, closeOnUpdateFeeOverflow = true)))
+ assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"03462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b")) == FeerateTolerance(0.75, 5.0, FeeratePerByte(5 sat).perKw, DustTolerance(40_000 sat, closeOnUpdateFeeOverflow = false)))
+ assert(nodeParams.onChainFeeConf.feerateToleranceFor(PublicKey(hex"0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f7")) == FeerateTolerance(0.5, 10.0, FeeratePerByte(10 sat).perKw, DustTolerance(50_000 sat, closeOnUpdateFeeOverflow = false)))
}
test("NodeParams should fail if htlc-minimum-msat is set to 0") {
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala
index 23fbc78..11db58f 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala
@@ -249,7 +249,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
val pubkeyScript = Script.write(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).toOption.get)
// We first receive some confirmed funds.
- miner.sendToPubkeyScript(pubkeyScript, 150_000 sat, FeeratePerKw(FeeratePerByte(5 sat))).pipeTo(sender.ref)
+ miner.sendToPubkeyScript(pubkeyScript, 150_000 sat, FeeratePerByte(5 sat).perKw).pipeTo(sender.ref)
val externalTxId = sender.expectMsgType[TxId]
generateBlocks(1)
@@ -294,7 +294,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
Seq(25 millibtc, 15 millibtc, 20 millibtc).foreach(amount => {
walletExternalFunds.getReceiveAddress().pipeTo(sender.ref)
val walletAddress = sender.expectMsgType[String]
- defaultWallet.sendToPubkeyScript(Script.write(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, walletAddress).toOption.get), amount, FeeratePerKw(FeeratePerByte(3.sat))).pipeTo(sender.ref)
+ defaultWallet.sendToPubkeyScript(Script.write(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, walletAddress).toOption.get), amount, FeeratePerByte(3.sat).perKw).pipeTo(sender.ref)
sender.expectMsgType[TxId]
})
@@ -442,7 +442,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
// When sending to a p2wpkh, bitcoin core should add a p2wpkh change output.
val pubkeyScript = Script.pay2wpkh(pubKey)
val unsignedTx = Transaction(version = 2, Nil, Seq(TxOut(150_000 sat, pubkeyScript)), lockTime = 0)
- bitcoinClient.fundTransaction(unsignedTx, feeRate = FeeratePerKw(FeeratePerByte(3 sat)), changePosition = Some(1)).pipeTo(sender.ref)
+ bitcoinClient.fundTransaction(unsignedTx, feeRate = FeeratePerByte(3 sat).perKw, changePosition = Some(1)).pipeTo(sender.ref)
val tx = sender.expectMsgType[FundTransactionResponse].tx
// We have a change output.
assert(tx.txOut.length == 2)
@@ -460,7 +460,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
// When sending to a p2tr, bitcoin core should add a p2tr change output.
val pubkeyScript = Script.pay2tr(pubKey.xOnly)
val unsignedTx = Transaction(version = 2, Nil, Seq(TxOut(150_000 sat, pubkeyScript)), lockTime = 0)
- bitcoinClient.fundTransaction(unsignedTx, feeRate = FeeratePerKw(FeeratePerByte(3 sat)), changePosition = Some(1)).pipeTo(sender.ref)
+ bitcoinClient.fundTransaction(unsignedTx, feeRate = FeeratePerByte(3 sat).perKw, changePosition = Some(1)).pipeTo(sender.ref)
val tx = sender.expectMsgType[FundTransactionResponse].tx
// We have a change output.
assert(tx.txOut.length == 2)
@@ -820,7 +820,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
val bitcoinClient = makeBitcoinCoreClient()
val txNotFunded = Transaction(2, Nil, Seq(TxOut(200_000 sat, Script.pay2wpkh(randomKey().publicKey))), 0)
- bitcoinClient.fundTransaction(txNotFunded, FeeratePerKw(FeeratePerByte(1 sat)), replaceable = true).pipeTo(sender.ref)
+ bitcoinClient.fundTransaction(txNotFunded, FeeratePerByte(1 sat).perKw, replaceable = true).pipeTo(sender.ref)
val txFunded1 = sender.expectMsgType[FundTransactionResponse].tx
assert(txFunded1.txIn.nonEmpty)
bitcoinClient.signPsbt(new Psbt(txFunded1), txFunded1.txIn.indices, Nil).pipeTo(sender.ref)
@@ -833,7 +833,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
sender.expectMsg(txFunded1.txIn.map(_.outPoint).toSet)
// we double-spend the inputs, which unlocks them
- bitcoinClient.fundTransaction(txFunded1, FeeratePerKw(FeeratePerByte(5 sat)), replaceable = true).pipeTo(sender.ref)
+ bitcoinClient.fundTransaction(txFunded1, FeeratePerByte(5 sat).perKw, replaceable = true).pipeTo(sender.ref)
val txFunded2 = sender.expectMsgType[FundTransactionResponse].tx
assert(txFunded2.txid != txFunded1.txid)
txFunded1.txIn.foreach(txIn => assert(txFunded2.txIn.map(_.outPoint).contains(txIn.outPoint)))
@@ -2078,7 +2078,7 @@ class BitcoinCoreClientWithEclairSignerSpec extends BitcoinCoreClientSpec {
val error = sender.expectMsgType[Failure]
assert(error.cause.getMessage.contains("Private keys are disabled for this wallet"))
- wallet.sendToPubkeyScript(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).toOption.get, 50_000.sat, FeeratePerKw(FeeratePerByte(5.sat))).pipeTo(sender.ref)
+ wallet.sendToPubkeyScript(addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).toOption.get, 50_000.sat, FeeratePerByte(5.sat).perKw).pipeTo(sender.ref)
sender.expectMsgType[TxId]
}
}
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala
index 0e285c5..ae3de19 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala
@@ -106,7 +106,7 @@ trait BitcoindService extends Logging {
.appendedAll(defaultAddressType_opt.map(addressType => s"addresstype=$addressType\n").getOrElse(""))
.appendedAll(changeAddressType_opt.map(addressType => s"changetype=$addressType\n").getOrElse(""))
.appendedAll(mempoolSize_opt.map(mempoolSize => s"maxmempool=$mempoolSize\n").getOrElse(""))
- .appendedAll(mempoolMinFeerate_opt.map(mempoolMinFeerate => s"minrelaytxfee=${FeeratePerKB(mempoolMinFeerate).feerate.toBtc.toBigDecimal}\n").getOrElse(""))
+ .appendedAll(mempoolMinFeerate_opt.map(mempoolMinFeerate => s"minrelaytxfee=${mempoolMinFeerate.perKB.feerate.toBtc.toBigDecimal}\n").getOrElse(""))
if (useCookie) {
defaultConf
.replace("rpcuser=foo", "")
@@ -248,7 +248,7 @@ trait BitcoindService extends Logging {
val tx = Transaction(version = 2, Nil, TxOut(amountSat, addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, address).toOption.get) :: Nil, lockTime = 0)
val client = makeBitcoinCoreClient()
val f = for {
- funded <- client.fundTransaction(tx, FeeratePerKw(FeeratePerByte(Satoshi(10))), replaceable = true)
+ funded <- client.fundTransaction(tx, FeeratePerByte(Satoshi(10)).perKw, replaceable = true)
signed <- client.signPsbt(new Psbt(funded.tx), funded.tx.txIn.indices, Nil)
txid <- client.publishTransaction(signed.finalTx_opt.toOption.get)
tx <- client.getTransaction(txid)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/FeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/FeeProviderSpec.scala
index 73c4d45..220eb22 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/FeeProviderSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/FeeProviderSpec.scala
@@ -26,14 +26,14 @@ class FeeProviderSpec extends AnyFunSuite {
assert(FeeratePerByte(FeeratePerKw(2000 sat)) == FeeratePerByte(8 sat))
assert(FeeratePerKB(FeeratePerByte(10 sat)) == FeeratePerKB(10000 sat))
assert(FeeratePerKB(FeeratePerKw(25 sat)) == FeeratePerKB(100 sat))
- assert(FeeratePerKw(FeeratePerKB(10000 sat)) == FeeratePerKw(2500 sat))
- assert(FeeratePerKw(FeeratePerByte(10 sat)) == FeeratePerKw(2500 sat))
+ assert(FeeratePerKB(10000 sat).perKw == FeeratePerKw(2500 sat))
+ assert(FeeratePerByte(10 sat).perKw == FeeratePerKw(2500 sat))
}
test("enforce a minimum feerate-per-kw") {
- assert(FeeratePerKw(FeeratePerKB(1000 sat)) == MinimumFeeratePerKw)
- assert(FeeratePerKw(FeeratePerKB(500 sat)) == MinimumFeeratePerKw)
- assert(FeeratePerKw(FeeratePerByte(1 sat)) == MinimumFeeratePerKw)
+ assert(FeeratePerKB(1000 sat).perKw == MinimumFeeratePerKw)
+ assert(FeeratePerKB(500 sat).perKw == MinimumFeeratePerKw)
+ assert(FeeratePerByte(1 sat).perKw == MinimumFeeratePerKw)
}
test("compare feerates") {
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/DustExposureSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/DustExposureSpec.scala
index aad9afd..657ca58 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/DustExposureSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/DustExposureSpec.scala
@@ -42,7 +42,7 @@ class DustExposureSpec extends AnyFunSuiteLike {
IncomingHtlc(createHtlc(3, 500.sat.toMilliSatoshi)),
OutgoingHtlc(createHtlc(3, 500.sat.toMilliSatoshi)),
)
- val spec = CommitmentSpec(htlcs, FeeratePerKw(FeeratePerByte(50 sat)), 50000 msat, 75000 msat)
+ val spec = CommitmentSpec(htlcs, FeeratePerByte(50 sat).perKw, 50000 msat, 75000 msat)
assert(DustExposure.computeExposure(spec, 450 sat, Transactions.ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) == 898.sat.toMilliSatoshi)
assert(DustExposure.computeExposure(spec, 500 sat, Transactions.ZeroFeeHtlcTxAnchorOutputsCommitmentFormat) == 2796.sat.toMilliSatoshi)
assert(DustExposure.computeExposure(spec, 500 sat, Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat) == 3796.sat.toMilliSatoshi)
@@ -50,7 +50,7 @@ class DustExposureSpec extends AnyFunSuiteLike {
{
// Low feerate: buffer adds 10 sat/byte
val dustLimit = 500.sat
- val feerate = FeeratePerKw(FeeratePerByte(10 sat))
+ val feerate = FeeratePerByte(10 sat).perKw
assert(Transactions.receivedHtlcTrimThreshold(dustLimit, feerate, Transactions.DefaultCommitmentFormat) == 2257.sat)
assert(Transactions.offeredHtlcTrimThreshold(dustLimit, feerate, Transactions.DefaultCommitmentFormat) == 2157.sat)
assert(Transactions.receivedHtlcTrimThreshold(dustLimit, feerate * 2, Transactions.DefaultCommitmentFormat) == 4015.sat)
@@ -81,7 +81,7 @@ class DustExposureSpec extends AnyFunSuiteLike {
{
// High feerate: buffer adds 25%
val dustLimit = 1000.sat
- val feerate = FeeratePerKw(FeeratePerByte(80 sat))
+ val feerate = FeeratePerByte(80 sat).perKw
assert(Transactions.receivedHtlcTrimThreshold(dustLimit, feerate, Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat) == 15120.sat)
assert(Transactions.offeredHtlcTrimThreshold(dustLimit, feerate, Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat) == 14320.sat)
assert(Transactions.receivedHtlcTrimThreshold(dustLimit, feerate * 1.25, Transactions.UnsafeLegacyAnchorOutputsCommitmentFormat) == 18650.sat)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala
index 8318941..a5302ae 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala
@@ -68,7 +68,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
val tx = Transaction(version = 2, Nil, TxOut(amount, addressToPublicKeyScript(Block.RegtestGenesisBlock.hash, walletAddress).toOption.get) :: Nil, lockTime = 0)
val client = makeBitcoinCoreClient()
val f = for {
- funded <- client.fundTransaction(tx, FeeratePerKw(FeeratePerByte(10.sat)))
+ funded <- client.fundTransaction(tx, FeeratePerByte(10.sat).perKw)
signed <- client.signPsbt(new Psbt(funded.tx), funded.tx.txIn.indices, Nil)
txid <- client.publishTransaction(signed.finalTx_opt.toOption.get)
} yield txid
@@ -2188,7 +2188,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
// Bob's available utxo is unconfirmed.
val probe = TestProbe()
walletB.getP2wpkhPubkey().pipeTo(probe.ref)
- walletB.sendToPubkeyScript(Script.write(Script.pay2wpkh(probe.expectMsgType[PublicKey])), 75_000 sat, FeeratePerKw(FeeratePerByte(1.sat))).pipeTo(probe.ref)
+ walletB.sendToPubkeyScript(Script.write(Script.pay2wpkh(probe.expectMsgType[PublicKey])), 75_000 sat, FeeratePerByte(1.sat).perKw).pipeTo(probe.ref)
probe.expectMsgType[TxId]
alice ! Start(alice2bob.ref)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala
index 5a14cc8..fee6d8a 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala
@@ -2458,7 +2458,7 @@ class NormalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with
assert(initialState.commitments.latest.localCommit.spec.commitTxFeerate == TestConstants.anchorOutputsFeeratePerKw)
val add = UpdateAddHtlc(ByteVector32.Zeroes, 0, 2500000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, Reputation.maxEndorsement, None)
alice2bob.send(bob, add)
- val fee = UpdateFee(initialState.channelId, FeeratePerKw(FeeratePerByte(2 sat)))
+ val fee = UpdateFee(initialState.channelId, FeeratePerByte(2 sat).perKw)
alice2bob.send(bob, fee)
awaitCond(bob.stateData == initialState
.modify(_.commitments.changes.remoteChanges.proposed).using(_ :+ add :+ fee)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala
index 5b09095..a9787a7 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/internal/channel/version4/ChannelCodecs4Spec.scala
@@ -111,7 +111,7 @@ class ChannelCodecs4Spec extends AnyFunSuite {
remoteFundingPubKey = PrivateKey(ByteVector.fromValidHex("01" * 32)).publicKey,
localOutputs = Nil,
commitmentFormat = ZeroFeeHtlcTxAnchorOutputsCommitmentFormat,
- lockTime = 0, dustLimit = 330.sat, targetFeerate = FeeratePerKw(FeeratePerByte(3.sat)), requireConfirmedInputs = RequireConfirmedInputs(forLocal = false, forRemote = false)),
+ lockTime = 0, dustLimit = 330.sat, targetFeerate = FeeratePerByte(3.sat).perKw, requireConfirmedInputs = RequireConfirmedInputs(forLocal = false, forRemote = false)),
liquidityPurchase_opt = None
)
assert(decoded == dualFundedUnconfirmedFundingTx)
diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LiquidityAdsSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LiquidityAdsSpec.scala
index 54610e7..0af254d 100644
--- a/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LiquidityAdsSpec.scala
+++ b/eclair-core/src/test/scala/fr/acinq/eclair/wire/protocol/LiquidityAdsSpec.scala
@@ -31,11 +31,11 @@ class LiquidityAdsSpec extends AnyFunSuite {
assert(nodeKey.publicKey == PublicKey(hex"03ca9b880627d2d4e3b33164f66946349f820d26aa9572fe0e525e534850cbd413"))
val fundingRate = LiquidityAds.FundingRate(100_000 sat, 1_000_000 sat, 500, 100, 10 sat, 1000 sat)
- assert(fundingRate.fees(FeeratePerKw(FeeratePerByte(5 sat)), 500_000 sat, 500_000 sat, isChannelCreation = false).total == 5635.sat)
- assert(fundingRate.fees(FeeratePerKw(FeeratePerByte(5 sat)), 500_000 sat, 600_000 sat, isChannelCreation = false).total == 5635.sat)
- assert(fundingRate.fees(FeeratePerKw(FeeratePerByte(5 sat)), 500_000 sat, 600_000 sat, isChannelCreation = true).total == 6635.sat)
- assert(fundingRate.fees(FeeratePerKw(FeeratePerByte(5 sat)), 500_000 sat, 400_000 sat, isChannelCreation = false).total == 4635.sat)
- assert(fundingRate.fees(FeeratePerKw(FeeratePerByte(10 sat)), 500_000 sat, 500_000 sat, isChannelCreation = false).total == 6260.sat)
+ assert(fundingRate.fees(FeeratePerByte(5 sat).perKw, 500_000 sat, 500_000 sat, isChannelCreation = false).total == 5635.sat)
+ assert(fundingRate.fees(FeeratePerByte(5 sat).perKw, 500_000 sat, 600_000 sat, isChannelCreation = false).total == 5635.sat)
+ assert(fundingRate.fees(FeeratePerByte(5 sat).perKw, 500_000 sat, 600_000 sat, isChannelCreation = true).total == 6635.sat)
+ assert(fundingRate.fees(FeeratePerByte(5 sat).perKw, 500_000 sat, 400_000 sat, isChannelCreation = false).total == 4635.sat)
+ assert(fundingRate.fees(FeeratePerByte(10 sat).perKw, 500_000 sat, 500_000 sat, isChannelCreation = false).total == 6260.sat)
val fundingRates = LiquidityAds.WillFundRates(fundingRate :: Nil, Set(LiquidityAds.PaymentType.FromChannelBalance))
val Some(request) = LiquidityAds.requestFunding(500_000 sat, LiquidityAds.PaymentDetails.FromChannelBalance, fundingRates)
diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala
index 0d606f3..8b8453d 100644
--- a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala
+++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Channel.scala
@@ -74,7 +74,7 @@ trait Channel {
val rbfOpen: Route = postRequest("rbfopen") { implicit f =>
formFields(channelIdFormParam, "targetFeerateSatByte".as[FeeratePerByte], "fundingFeeBudgetSatoshis".as[Satoshi], "lockTime".as[Long].?) {
- (channelId, targetFeerateSatByte, fundingFeeBudget, lockTime_opt) => complete(eclairApi.rbfOpen(channelId, FeeratePerKw(targetFeerateSatByte), fundingFeeBudget, lockTime_opt))
+ (channelId, targetFeerateSatByte, fundingFeeBudget, lockTime_opt) => complete(eclairApi.rbfOpen(channelId, targetFeerateSatByte.perKw, fundingFeeBudget, lockTime_opt))
}
}
@@ -95,7 +95,7 @@ trait Channel {
val rbfSplice: Route = postRequest("rbfsplice") { implicit f =>
formFields(channelIdFormParam, "targetFeerateSatByte".as[FeeratePerByte], "fundingFeeBudgetSatoshis".as[Satoshi], "lockTime".as[Long].?) {
- (channelId, targetFeerateSatByte, fundingFeeBudget, lockTime_opt) => complete(eclairApi.rbfSplice(channelId, FeeratePerKw(targetFeerateSatByte), fundingFeeBudget, lockTime_opt))
+ (channelId, targetFeerateSatByte, fundingFeeBudget, lockTime_opt) => complete(eclairApi.rbfSplice(channelId, targetFeerateSatByte.perKw, fundingFeeBudget, lockTime_opt))
}
}
@@ -104,9 +104,9 @@ trait Channel {
formFields("scriptPubKey".as[ByteVector](bytesUnmarshaller).?, "preferredFeerateSatByte".as[FeeratePerByte].?, "minFeerateSatByte".as[FeeratePerByte].?, "maxFeerateSatByte".as[FeeratePerByte].?) {
(scriptPubKey_opt, preferredFeerate_opt, minFeerate_opt, maxFeerate_opt) =>
val closingFeerates = preferredFeerate_opt.map(preferredPerByte => {
- val preferredFeerate = FeeratePerKw(preferredPerByte)
- val minFeerate = minFeerate_opt.map(feerate => FeeratePerKw(feerate)).getOrElse(preferredFeerate / 2)
- val maxFeerate = maxFeerate_opt.map(feerate => FeeratePerKw(feerate)).getOrElse(preferredFeerate * 2)
+ val preferredFeerate = preferredPerByte.perKw
+ val minFeerate = minFeerate_opt.map(feerate => feerate.perKw).getOrElse(preferredFeerate / 2)
+ val maxFeerate = maxFeerate_opt.map(feerate => feerate.perKw).getOrElse(preferredFeerate * 2)
ClosingFeerates(preferredFeerate, minFeerate, maxFeerate)
})
if (scriptPubKey_opt.forall(Script.isNativeWitnessScript)) {
@@ -121,7 +121,7 @@ trait Channel {
val forceClose: Route = postRequest("forceclose") { implicit t =>
withChannelsIdentifier { channels =>
formFields("maxClosingFeerateSatByte".as[FeeratePerByte].?) { maxClosingFeerate_opt =>
- complete(eclairApi.forceClose(channels, maxClosingFeerate_opt.map(FeeratePerKw(_))))
+ complete(eclairApi.forceClose(channels, maxClosingFeerate_opt.map(_.perKw)))
}
}
}
diff --git a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Control.scala b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Control.scala
index bffb9b1..f5892a7 100644
--- a/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Control.scala
+++ b/eclair-node/src/main/scala/fr/acinq/eclair/api/handlers/Control.scala
@@ -57,7 +57,7 @@ trait Control {
val spendFromChannelAddressPrep: Route = postRequest("spendfromchanneladdressprep") { implicit t =>
formFields("t".as[ByteVector32], "o".as[Int], "kp", "fi".as[Int], "address", "f".as[FeeratePerByte]) {
(txId, outputIndex, keyPath, fundingTxIndex, address, feerate) =>
- complete(eclairApi.spendFromChannelAddressPrep(OutPoint(TxId(txId), outputIndex), KeyPath(keyPath), fundingTxIndex, address, FeeratePerKw(feerate)))
+ complete(eclairApi.spendFromChannelAddressPrep(OutPoint(TxId(txId), outputIndex), KeyPath(keyPath), fundingTxIndex, address, feerate.perKw))
}
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.