Skip to content

Commit

Permalink
Purchase liquidity using a splice
Browse files Browse the repository at this point in the history
We allow purchasing inbound liquidity by initiating an empty splice,
similar to what we do for CPFP. If the remote doesn't fund, or its rates
are too expensive,  we immediately abort the splice attempt.
  • Loading branch information
t-bast committed Nov 29, 2023
1 parent c1f0b1b commit d698cd9
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import fr.acinq.lightning.utils.UUID
import fr.acinq.lightning.utils.msat
import fr.acinq.lightning.wire.FailureMessage
import fr.acinq.lightning.wire.LightningMessage
import fr.acinq.lightning.wire.LiquidityAds
import fr.acinq.lightning.wire.OnionRoutingPacket
import kotlinx.coroutines.CompletableDeferred
import fr.acinq.lightning.wire.Init as InitMessage
Expand Down Expand Up @@ -83,7 +84,7 @@ sealed class ChannelCommand {
data class UpdateFee(val feerate: FeeratePerKw, val commit: Boolean = false) : Commitment(), ForbiddenDuringSplice
object CheckHtlcTimeout : Commitment()
sealed class Splice : Commitment() {
data class Request(val replyTo: CompletableDeferred<Response>, val spliceIn: SpliceIn?, val spliceOut: SpliceOut?, val feerate: FeeratePerKw, val origins: List<Origin.PayToOpenOrigin> = emptyList()) : Splice() {
data class Request(val replyTo: CompletableDeferred<Response>, val spliceIn: SpliceIn?, val spliceOut: SpliceOut?, val requestRemoteFunding: LiquidityAds.RequestRemoteFunding?, val feerate: FeeratePerKw, val origins: List<Origin.PayToOpenOrigin> = emptyList()) : Splice() {
val pushAmount: MilliSatoshi = spliceIn?.pushAmount ?: 0.msat
val spliceOutputs: List<TxOut> = spliceOut?.let { listOf(TxOut(it.amount, it.scriptPubKey)) } ?: emptyList()

Expand All @@ -101,14 +102,16 @@ sealed class ChannelCommand {
val fundingTxIndex: Long,
val fundingTxId: TxId,
val capacity: Satoshi,
val balance: MilliSatoshi
val balance: MilliSatoshi,
val liquidityPurchased: LiquidityAds.Lease?,
) : Response()

sealed class Failure : Response() {
object InsufficientFunds : Failure()
object InvalidSpliceOutPubKeyScript : Failure()
object SpliceAlreadyInProgress : Failure()
object ChannelNotIdle : Failure()
data class InvalidLiquidityAds(val reason: ChannelException) : Failure()
data class FundingFailure(val reason: FundingContributionFailure) : Failure()
object CannotStartSession : Failure()
data class InteractiveTxSessionFailed(val reason: InteractiveTxSessionAction.RemoteFailure) : Failure()
Expand Down
15 changes: 12 additions & 3 deletions src/commonMain/kotlin/fr/acinq/lightning/channel/InteractiveTx.kt
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,7 @@ data class InteractiveTxSigningSession(
sharedTx: SharedTransaction,
localPushAmount: MilliSatoshi,
remotePushAmount: MilliSatoshi,
liquidityPurchased: LiquidityAds.Lease?,
localCommitmentIndex: Long,
remoteCommitmentIndex: Long,
commitTxFeerate: FeeratePerKw,
Expand All @@ -834,13 +835,14 @@ data class InteractiveTxSigningSession(
val channelKeys = channelParams.localParams.channelKeys(keyManager)
val unsignedTx = sharedTx.buildUnsignedTx()
val sharedOutputIndex = unsignedTx.txOut.indexOfFirst { it.publicKeyScript == fundingParams.fundingPubkeyScript(channelKeys) }
val liquidityFees = liquidityPurchased?.fees?.toMilliSatoshi() ?: 0.msat
return Helpers.Funding.makeCommitTxsWithoutHtlcs(
channelKeys,
channelParams.channelId,
channelParams.localParams, channelParams.remoteParams,
fundingAmount = sharedTx.sharedOutput.amount,
toLocal = sharedTx.sharedOutput.localAmount - localPushAmount + remotePushAmount,
toRemote = sharedTx.sharedOutput.remoteAmount - remotePushAmount + localPushAmount,
toLocal = sharedTx.sharedOutput.localAmount - localPushAmount + remotePushAmount - liquidityFees,
toRemote = sharedTx.sharedOutput.remoteAmount - remotePushAmount + localPushAmount + liquidityFees,
localCommitmentIndex = localCommitmentIndex,
remoteCommitmentIndex = remoteCommitmentIndex,
commitTxFeerate,
Expand Down Expand Up @@ -900,7 +902,14 @@ sealed class RbfStatus {
sealed class SpliceStatus {
object None : SpliceStatus()
data class Requested(val command: ChannelCommand.Commitment.Splice.Request, val spliceInit: SpliceInit) : SpliceStatus()
data class InProgress(val replyTo: CompletableDeferred<ChannelCommand.Commitment.Splice.Response>?, val spliceSession: InteractiveTxSession, val localPushAmount: MilliSatoshi, val remotePushAmount: MilliSatoshi, val origins: List<Origin.PayToOpenOrigin>) : SpliceStatus()
data class InProgress(
val replyTo: CompletableDeferred<ChannelCommand.Commitment.Splice.Response>?,
val spliceSession: InteractiveTxSession,
val localPushAmount: MilliSatoshi,
val remotePushAmount: MilliSatoshi,
val liquidityPurchased: LiquidityAds.Lease?,
val origins: List<Origin.PayToOpenOrigin>
) : SpliceStatus()
data class WaitingForSigs(val session: InteractiveTxSigningSession, val origins: List<Origin.PayToOpenOrigin>) : SpliceStatus()
object Aborted : SpliceStatus()
}
Loading

0 comments on commit d698cd9

Please sign in to comment.