@@ -98,6 +98,20 @@ data class InteractiveTxParams(
9898 val fundingTxIndex = (sharedInput as ? SharedFundingInput .Multisig2of2 )?.let { it.fundingTxIndex + 1 } ? : 0
9999 return Helpers .Funding .makeFundingPubKeyScript(channelKeys.fundingPubKey(fundingTxIndex), remoteFundingPubkey)
100100 }
101+
102+ fun liquidityFees (purchase : LiquidityAds .Purchase ? ): MilliSatoshi = purchase?.let { l ->
103+ val fees = when (l) {
104+ is LiquidityAds .Purchase .Standard -> l.fees.total.toMilliSatoshi()
105+ is LiquidityAds .Purchase .WithFeeCredit -> l.fees.total.toMilliSatoshi() - l.feeCreditUsed
106+ }
107+ when (l.paymentDetails) {
108+ is LiquidityAds .PaymentDetails .FromChannelBalance -> if (isInitiator) fees else - fees
109+ is LiquidityAds .PaymentDetails .FromChannelBalanceForFutureHtlc -> if (isInitiator) fees else - fees
110+ // Fees will be paid later, from relayed HTLCs.
111+ is LiquidityAds .PaymentDetails .FromFutureHtlc -> 0 .msat
112+ is LiquidityAds .PaymentDetails .FromFutureHtlcWithPreimage -> 0 .msat
113+ }
114+ } ? : 0 .msat
101115}
102116
103117sealed class InteractiveTxInput {
@@ -209,7 +223,12 @@ sealed class InteractiveTxOutput {
209223 */
210224 data class Remote (override val serialId : Long , override val amount : Satoshi , override val pubkeyScript : ByteVector ) : InteractiveTxOutput(), Incoming
211225
212- /* * The shared output can be added by us or by our peer, depending on who initiated the protocol. */
226+ /* *
227+ * The shared output can be added by us or by our peer, depending on who initiated the protocol.
228+ *
229+ * @param localAmount amount contributed by us, before applying push_amount and (optional) liquidity fees: this is different from the channel balance.
230+ * @param remoteAmount amount contributed by our peer, before applying push_amount and (optional) liquidity fees: this is different from the channel balance.
231+ */
213232 data class Shared (override val serialId : Long , override val pubkeyScript : ByteVector , val localAmount : MilliSatoshi , val remoteAmount : MilliSatoshi , val htlcAmount : MilliSatoshi ) : InteractiveTxOutput(), Incoming, Outgoing {
214233 // Note that the truncation is a no-op: the sum of balances in a channel must be a satoshi amount.
215234 override val amount: Satoshi = (localAmount + remoteAmount + htlcAmount).truncateToSatoshi()
@@ -246,8 +265,17 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
246265 /* *
247266 * @param walletInputs 2-of-2 swap-in wallet inputs.
248267 */
249- fun create (channelKeys : KeyManager .ChannelKeys , swapInKeys : KeyManager .SwapInOnChainKeys , params : InteractiveTxParams , walletInputs : List <WalletState .Utxo >): Either <FundingContributionFailure , FundingContributions > =
250- create(channelKeys, swapInKeys, params, null , walletInputs, listOf ())
268+ fun create (
269+ channelKeys : KeyManager .ChannelKeys ,
270+ swapInKeys : KeyManager .SwapInOnChainKeys ,
271+ params : InteractiveTxParams ,
272+ walletInputs : List <WalletState .Utxo >,
273+ localPushAmount : MilliSatoshi ,
274+ remotePushAmount : MilliSatoshi ,
275+ liquidityPurchase : LiquidityAds .Purchase ?
276+ ): Either <FundingContributionFailure , FundingContributions > {
277+ return create(channelKeys, swapInKeys, params, null , walletInputs, listOf (), localPushAmount, remotePushAmount, liquidityPurchase)
278+ }
251279
252280 /* *
253281 * @param sharedUtxo previous input shared between the two participants (e.g. previous funding output when splicing) and our corresponding balance.
@@ -262,6 +290,9 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
262290 sharedUtxo : Pair <SharedFundingInput , SharedFundingInputBalances >? ,
263291 walletInputs : List <WalletState .Utxo >,
264292 localOutputs : List <TxOut >,
293+ localPushAmount : MilliSatoshi ,
294+ remotePushAmount : MilliSatoshi ,
295+ liquidityPurchase : LiquidityAds .Purchase ? ,
265296 changePubKey : PublicKey ? = null
266297 ): Either <FundingContributionFailure , FundingContributions > {
267298 walletInputs.forEach { utxo ->
@@ -277,14 +308,18 @@ data class FundingContributions(val inputs: List<InteractiveTxInput.Outgoing>, v
277308 return Either .Left (FundingContributionFailure .NotEnoughFunding (params.localContribution, localOutputs.map { it.amount }.sum(), totalAmountIn))
278309 }
279310
280- val nextLocalBalance = (sharedUtxo?.second?.toLocal ? : 0 .msat) + params.localContribution.toMilliSatoshi()
281- val nextRemoteBalance = (sharedUtxo?.second?.toRemote ? : 0 .msat) + params.remoteContribution.toMilliSatoshi()
282- if (nextLocalBalance < 0 .msat || nextRemoteBalance < 0 .msat) {
283- return Either .Left (FundingContributionFailure .InvalidFundingBalances (params.fundingAmount, nextLocalBalance, nextRemoteBalance))
311+ val liquidityFees = params.liquidityFees(liquidityPurchase)
312+ val nextLocalBalanceBeforePush = (sharedUtxo?.second?.toLocal ? : 0 .msat) + params.localContribution.toMilliSatoshi()
313+ val nextLocalBalanceAfterPush = (sharedUtxo?.second?.toLocal ? : 0 .msat) + params.localContribution.toMilliSatoshi() - localPushAmount + remotePushAmount - liquidityFees
314+ val nextRemoteBalanceBeforePush = (sharedUtxo?.second?.toRemote ? : 0 .msat) + params.remoteContribution.toMilliSatoshi()
315+ val nextRemoteBalanceAfterPush = (sharedUtxo?.second?.toRemote ? : 0 .msat) + params.remoteContribution.toMilliSatoshi() + localPushAmount - remotePushAmount + liquidityFees
316+ if (nextLocalBalanceAfterPush < 0 .msat || nextRemoteBalanceAfterPush < 0 .msat) {
317+ return Either .Left (FundingContributionFailure .InvalidFundingBalances (params.fundingAmount, nextLocalBalanceAfterPush, nextRemoteBalanceAfterPush))
284318 }
285319
286320 val fundingPubkeyScript = params.fundingPubkeyScript(channelKeys)
287- val sharedOutput = listOf (InteractiveTxOutput .Shared (0 , fundingPubkeyScript, nextLocalBalance, nextRemoteBalance, sharedUtxo?.second?.toHtlcs ? : 0 .msat))
321+ // We use local and remote balances before amounts are pushed to allow computing the local and remote mining fees.
322+ val sharedOutput = listOf (InteractiveTxOutput .Shared (0 , fundingPubkeyScript, nextLocalBalanceBeforePush, nextRemoteBalanceBeforePush, sharedUtxo?.second?.toHtlcs ? : 0 .msat))
288323 val nonChangeOutputs = localOutputs.map { o -> InteractiveTxOutput .Local .NonChange (0 , o.amount, o.publicKeyScript) }
289324 val changeOutput = when (changePubKey) {
290325 null -> listOf ()
@@ -1068,16 +1103,7 @@ data class InteractiveTxSigningSession(
10681103 val channelKeys = channelParams.localParams.channelKeys(keyManager)
10691104 val unsignedTx = sharedTx.buildUnsignedTx()
10701105 val sharedOutputIndex = unsignedTx.txOut.indexOfFirst { it.publicKeyScript == fundingParams.fundingPubkeyScript(channelKeys) }
1071- val liquidityFees = liquidityPurchase?.let { l ->
1072- val fees = l.fees.total.toMilliSatoshi()
1073- when (l.paymentDetails) {
1074- is LiquidityAds .PaymentDetails .FromChannelBalance -> if (fundingParams.isInitiator) fees else - fees
1075- is LiquidityAds .PaymentDetails .FromChannelBalanceForFutureHtlc -> if (fundingParams.isInitiator) fees else - fees
1076- // Fees will be paid later, from relayed HTLCs.
1077- is LiquidityAds .PaymentDetails .FromFutureHtlc -> 0 .msat
1078- is LiquidityAds .PaymentDetails .FromFutureHtlcWithPreimage -> 0 .msat
1079- }
1080- } ? : 0 .msat
1106+ val liquidityFees = fundingParams.liquidityFees(liquidityPurchase)
10811107 return Helpers .Funding .makeCommitTxs(
10821108 channelKeys,
10831109 channelParams.channelId,
0 commit comments