@@ -22,7 +22,7 @@ import akka.actor.typed.scaladsl.adapter.TypedActorRefOps
2222import  akka .actor .typed .scaladsl .{ActorContext , Behaviors }
2323import  akka .actor .typed .{ActorRef , Behavior }
2424import  fr .acinq .bitcoin .scalacompat .Crypto .PublicKey 
25- import  fr .acinq .bitcoin .scalacompat .{BtcDouble , ByteVector32 , Satoshi , Script }
25+ import  fr .acinq .bitcoin .scalacompat .{BtcDouble , ByteVector32 , Satoshi , SatoshiLong ,  Script }
2626import  fr .acinq .eclair .Features .Wumbo 
2727import  fr .acinq .eclair .blockchain .OnchainPubkeyCache 
2828import  fr .acinq .eclair .channel ._ 
@@ -84,8 +84,8 @@ object OpenChannelInterceptor {
8484      }
8585    }
8686
87-   def  makeChannelParams (nodeParams : NodeParams , initFeatures :  Features [ InitFeature ],  upfrontShutdownScript_opt :  Option [ ByteVector ],  walletStaticPaymentBasepoint_opt :  Option [ PublicKey ],  isChannelOpener :  Boolean ,  paysCommitTxFees :  Boolean ,  dualFunded :  Boolean ,  fundingAmount : Satoshi , unlimitedMaxHtlcValueInFlight : Boolean ):  LocalParams  =  {
88-     val   maxHtlcValueInFlightMsat   =   if  (unlimitedMaxHtlcValueInFlight) {
87+   private   def  computeMaxHtlcValueInFlight (nodeParams : NodeParams , fundingAmount : Satoshi , unlimitedMaxHtlcValueInFlight : Boolean ):  MilliSatoshi  =  {
88+     if  (unlimitedMaxHtlcValueInFlight) {
8989      //  We don't want to impose limits on the amount in flight, typically to allow fully emptying the channel.
9090      21e6 .btc.toMilliSatoshi
9191    } else  {
@@ -94,11 +94,14 @@ object OpenChannelInterceptor {
9494      //  base it on the amount that we're contributing instead of the total funding amount.
9595      nodeParams.channelConf.maxHtlcValueInFlightMsat.min(fundingAmount *  nodeParams.channelConf.maxHtlcValueInFlightPercent /  100 )
9696    }
97+   }
98+ 
99+   def  makeChannelParams (nodeParams : NodeParams , initFeatures : Features [InitFeature ], upfrontShutdownScript_opt : Option [ByteVector ], walletStaticPaymentBasepoint_opt : Option [PublicKey ], isChannelOpener : Boolean , paysCommitTxFees : Boolean , dualFunded : Boolean , fundingAmount : Satoshi , unlimitedMaxHtlcValueInFlight : Boolean ):  LocalParams  =  {
97100    LocalParams (
98101      nodeParams.nodeId,
99102      nodeParams.channelKeyManager.newFundingKeyPath(isChannelOpener), //  we make sure that opener and non-opener key paths end differently
100103      dustLimit =  nodeParams.channelConf.dustLimit,
101-       maxHtlcValueInFlightMsat =  maxHtlcValueInFlightMsat ,
104+       maxHtlcValueInFlightMsat =  computeMaxHtlcValueInFlight(nodeParams, fundingAmount, unlimitedMaxHtlcValueInFlight) ,
102105      initialRequestedChannelReserve_opt =  if  (dualFunded) None  else  Some ((fundingAmount *  nodeParams.channelConf.reserveToFundingRatio).max(nodeParams.channelConf.dustLimit)), //  BOLT #2: make sure that our reserve is above our dust limit
103106      htlcMinimum =  nodeParams.channelConf.htlcMinimum,
104107      toSelfDelay =  nodeParams.channelConf.toRemoteDelay, //  we choose their delay
@@ -142,7 +145,9 @@ private class OpenChannelInterceptor(peer: ActorRef[Any],
142145      val  channelType  =  request.open.channelType_opt.getOrElse(ChannelTypes .defaultFromFeatures(request.localFeatures, request.remoteFeatures, channelFlags.announceChannel))
143146      val  dualFunded  =  Features .canUseFeature(request.localFeatures, request.remoteFeatures, Features .DualFunding )
144147      val  upfrontShutdownScript  =  Features .canUseFeature(request.localFeatures, request.remoteFeatures, Features .UpfrontShutdownScript )
145-       val  localParams  =  createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isChannelOpener =  true , paysCommitTxFees =  true , dualFunded =  dualFunded, request.open.fundingAmount, request.open.disableMaxHtlcValueInFlight)
148+       //  If we're purchasing liquidity, we expect our peer to contribute at least the amount we're purchasing, otherwise we'll cancel the funding attempt.
149+       val  expectedFundingAmount  =  request.open.fundingAmount +  request.open.requestFunding_opt.map(_.requestedAmount).getOrElse(0  sat)
150+       val  localParams  =  createLocalParams(nodeParams, request.localFeatures, upfrontShutdownScript, channelType, isChannelOpener =  true , paysCommitTxFees =  true , dualFunded =  dualFunded, expectedFundingAmount, request.open.disableMaxHtlcValueInFlight)
146151      peer !  Peer .SpawnChannelInitiator (request.replyTo, request.open, ChannelConfig .standard, channelType, localParams)
147152      waitForRequest()
148153    }
@@ -210,7 +215,10 @@ private class OpenChannelInterceptor(peer: ActorRef[Any],
210215        request.open.fold(_ =>  None , _.requestFunding_opt) match  {
211216          case  Some (requestFunding) if  Features .canUseFeature(request.localFeatures, request.remoteFeatures, Features .OnTheFlyFunding ) &&  localParams.paysCommitTxFees => 
212217            val  addFunding  =  LiquidityAds .AddFunding (requestFunding.requestedAmount, nodeParams.liquidityAdsConfig.rates_opt)
213-             val  accept  =  SpawnChannelNonInitiator (request.open, ChannelConfig .standard, channelType, Some (addFunding), localParams, request.peerConnection.toClassic)
218+             //  Now that we know how much we'll contribute to the funding transaction, we update the maxHtlcValueInFlight.
219+             val  maxHtlcValueInFlight  =  localParams.maxHtlcValueInFlightMsat.max(computeMaxHtlcValueInFlight(nodeParams, request.fundingAmount +  addFunding.fundingAmount, unlimitedMaxHtlcValueInFlight =  false ))
220+             val  localParams1  =  localParams.copy(maxHtlcValueInFlightMsat =  maxHtlcValueInFlight)
221+             val  accept  =  SpawnChannelNonInitiator (request.open, ChannelConfig .standard, channelType, Some (addFunding), localParams1, request.peerConnection.toClassic)
214222            checkNoExistingChannel(request, accept)
215223          case  _ => 
216224            //  We don't honor liquidity ads for new channels: node operators should use plugin for that.
0 commit comments