@@ -40,17 +40,13 @@ import fr.acinq.lightning.bin.logs.stringTimestamp
40
40
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceClient
41
41
import fr.acinq.lightning.blockchain.mempool.MempoolSpaceWatcher
42
42
import fr.acinq.lightning.crypto.LocalKeyManager
43
- import fr.acinq.lightning.db.ChannelsDb
44
- import fr.acinq.lightning.db.Databases
45
- import fr.acinq.lightning.db.PaymentsDb
43
+ import fr.acinq.lightning.db.*
46
44
import fr.acinq.lightning.io.Peer
47
45
import fr.acinq.lightning.io.TcpSocket
48
46
import fr.acinq.lightning.logging.LoggerFactory
49
47
import fr.acinq.lightning.payment.LiquidityPolicy
50
- import fr.acinq.lightning.utils.Connection
51
- import fr.acinq.lightning.utils.msat
52
- import fr.acinq.lightning.utils.sat
53
- import fr.acinq.lightning.utils.toByteVector
48
+ import fr.acinq.lightning.utils.*
49
+ import fr.acinq.lightning.wire.LiquidityAds
54
50
import fr.acinq.phoenix.db.*
55
51
import io.ktor.http.*
56
52
import io.ktor.server.application.*
@@ -90,14 +86,14 @@ class Phoenixd : CliktCommand() {
90
86
}
91
87
private val agreeToTermsOfService by option(" --agree-to-terms-of-service" , hidden = true , help = " Agree to terms of service" ).flag()
92
88
private val chain by option(" --chain" , help = " Bitcoin chain to use" ).choice(
93
- " mainnet" to Chain .Mainnet , " testnet" to Chain .Testnet
89
+ " mainnet" to Chain .Mainnet , " testnet" to Chain .Testnet3
94
90
).default(Chain .Mainnet , defaultForHelp = " mainnet" )
95
91
private val mempoolSpaceUrl by option(" --mempool-space-url" , help = " Custom mempool.space instance" )
96
92
.convert { Url (it) }
97
93
.defaultLazy {
98
94
when (chain) {
99
95
Chain .Mainnet -> MempoolSpaceClient .OfficialMempoolMainnet
100
- Chain .Testnet -> MempoolSpaceClient .OfficialMempoolTestnet
96
+ Chain .Testnet3 -> MempoolSpaceClient .OfficialMempoolTestnet
101
97
else -> error(" unsupported chain" )
102
98
}
103
99
}
@@ -155,7 +151,7 @@ class Phoenixd : CliktCommand() {
155
151
" off" to 0 .sat,
156
152
" 50k" to 50_000 .sat,
157
153
" 100k" to 100_000 .sat,
158
- ).default(100_000 .sat, " 100k" )
154
+ ).convert { it.toMilliSatoshi() }. default(100_000 .sat.toMilliSatoshi() , " 100k" )
159
155
private val maxRelativeFeePct by option(" --max-relative-fee-percent" , help = " Max relative fee for on-chain operations in percent." , hidden = true )
160
156
.int()
161
157
.restrictTo(1 .. 50 )
@@ -244,10 +240,11 @@ class Phoenixd : CliktCommand() {
244
240
)
245
241
val lsp = LSP .from(chain)
246
242
val liquidityPolicy = LiquidityPolicy .Auto (
247
- maxMiningFee = liquidityOptions.maxMiningFee,
243
+ inboundLiquidityTarget = liquidityOptions.autoLiquidity,
244
+ maxAbsoluteFee = liquidityOptions.maxMiningFee,
248
245
maxRelativeFeeBasisPoints = liquidityOptions.maxRelativeFeeBasisPoints,
249
- skipMiningFeeCheck = false ,
250
- maxAllowedCredit = liquidityOptions.maxFeeCredit
246
+ skipAbsoluteFeeCheck = false ,
247
+ maxAllowedFeeCredit = liquidityOptions.maxFeeCredit
251
248
)
252
249
val keyManager = LocalKeyManager (seed.seed, chain, lsp.swapInXpub)
253
250
val nodeParams = NodeParams (chain, loggerFactory, keyManager)
@@ -276,9 +273,6 @@ class Phoenixd : CliktCommand() {
276
273
channel_close_outgoing_paymentsAdapter = Channel_close_outgoing_payments .Adapter (
277
274
closing_info_typeAdapter = EnumColumnAdapter ()
278
275
),
279
- inbound_liquidity_outgoing_paymentsAdapter = Inbound_liquidity_outgoing_payments .Adapter (
280
- lease_typeAdapter = EnumColumnAdapter ()
281
- )
282
276
)
283
277
val channelsDb = SqliteChannelsDb (driver, database)
284
278
val paymentsDb = SqlitePaymentsDb (database)
@@ -324,39 +318,59 @@ class Phoenixd : CliktCommand() {
324
318
}
325
319
launch {
326
320
nodeParams.nodeEvents
327
- .filterIsInstance<PaymentEvents .PaymentReceived >()
328
- .filter { it.amount > 0 .msat }
321
+ .filterIsInstance<PaymentEvents >()
329
322
.collect {
330
- consoleLog(" received lightning payment: ${it.amount.truncateToSatoshi()} (${it.receivedWith.joinToString { part -> part::class .simpleName.toString().lowercase() }} )" )
323
+ when (it) {
324
+ is PaymentEvents .PaymentReceived -> {
325
+ val fee = it.receivedWith.filterIsInstance<IncomingPayment .ReceivedWith .LightningPayment >().map { it.fundingFee?.amount ? : 0 .msat }.sum().truncateToSatoshi()
326
+ val type = it.receivedWith.joinToString { part -> part::class .simpleName.toString().lowercase() }
327
+ consoleLog(" received lightning payment: ${it.amount.truncateToSatoshi()} ($type${if (fee > 0 .sat) " fee=$fee " else " " } )" )
328
+ }
329
+ is PaymentEvents .PaymentSent ->
330
+ when (val payment = it.payment) {
331
+ is InboundLiquidityOutgoingPayment -> {
332
+ val totalFee = payment.fees.truncateToSatoshi()
333
+ val feePaidFromBalance = payment.feePaidFromChannelBalance.total
334
+ val feePaidFromFeeCredit = payment.feeCreditUsed.truncateToSatoshi()
335
+ val feeRemaining = totalFee - feePaidFromBalance - feePaidFromFeeCredit
336
+ val purchaseType = payment.purchase.paymentDetails.paymentType::class .simpleName.toString().lowercase()
337
+ consoleLog(" purchased inbound liquidity: ${payment.purchase.amount} (totalFee=$totalFee feePaidFromBalance=$feePaidFromBalance feePaidFromFeeCredit=$feePaidFromFeeCredit feeRemaining=$feeRemaining purchaseType=$purchaseType )" )
338
+ }
339
+ else -> {}
340
+ }
341
+ }
331
342
}
332
343
}
333
344
launch {
334
345
nodeParams.nodeEvents
335
- .filterIsInstance<LiquidityEvents .Decision . Rejected >()
346
+ .filterIsInstance<LiquidityEvents .Rejected >()
336
347
.collect {
337
348
when (val reason = it.reason) {
338
- is LiquidityEvents .Decision .Rejected .Reason .OverMaxCredit -> {
339
- consoleLog(yellow(" lightning payment rejected (amount=${it.amount.truncateToSatoshi()} ): over max fee credit (max=${reason.maxAllowedCredit} )" ))
340
- }
341
- is LiquidityEvents .Decision .Rejected .Reason .TooExpensive .OverMaxMiningFee -> {
342
- consoleLog(yellow(" lightning payment rejected (amount=${it.amount.truncateToSatoshi()} ): over max mining fee (max=${reason.maxMiningFee} )" ))
343
- }
344
- is LiquidityEvents .Decision .Rejected .Reason .TooExpensive .OverRelativeFee -> {
345
- consoleLog(yellow(" lightning payment rejected (amount=${it.amount.truncateToSatoshi()} ): fee=${it.fee.truncateToSatoshi()} more than ${reason.maxRelativeFeeBasisPoints.toDouble() / 100 } % of amount" ))
346
- }
347
- LiquidityEvents .Decision .Rejected .Reason .ChannelInitializing -> {
348
- consoleLog(yellow(" channels are initializing" ))
349
- }
350
- LiquidityEvents .Decision .Rejected .Reason .PolicySetToDisabled -> {
349
+ // TODO: put this back after rework of LiquidityPolicy to handle fee credit
350
+ // is LiquidityEvents.Rejected.Reason.OverMaxCredit -> {
351
+ // consoleLog(yellow("lightning payment rejected (amount=${it.amount.truncateToSatoshi()}): over max fee credit (max=${reason.maxAllowedCredit})"))
352
+ // }
353
+ is LiquidityEvents .Rejected .Reason .TooExpensive .OverAbsoluteFee ->
354
+ consoleLog(yellow(" lightning payment rejected (amount=${it.amount.truncateToSatoshi()} ): over absolute fee (fee=${it.fee.truncateToSatoshi()} max=${reason.maxAbsoluteFee} )" ))
355
+ is LiquidityEvents .Rejected .Reason .TooExpensive .OverRelativeFee ->
356
+ consoleLog(yellow(" lightning payment rejected (amount=${it.amount.truncateToSatoshi()} ): over relative fee (fee=${it.fee.truncateToSatoshi()} max=${reason.maxRelativeFeeBasisPoints.toDouble() / 100 } %)" ))
357
+ LiquidityEvents .Rejected .Reason .PolicySetToDisabled ->
351
358
consoleLog(yellow(" automated liquidity is disabled" ))
352
- }
359
+ LiquidityEvents .Rejected .Reason .ChannelFundingInProgress ->
360
+ consoleLog(yellow(" channel operation is in progress" ))
361
+ is LiquidityEvents .Rejected .Reason .MissingOffChainAmountTooLow ->
362
+ consoleLog(yellow(" missing offchain amount is too low (missingOffChainAmount=${reason.missingOffChainAmount} currentFeeCredit=${reason.currentFeeCredit} " ))
363
+ LiquidityEvents .Rejected .Reason .NoMatchingFundingRate ->
364
+ consoleLog(yellow(" no matching funding rates" ))
365
+ is LiquidityEvents .Rejected .Reason .TooManyParts ->
366
+ consoleLog(yellow(" too many payment parts" ))
353
367
}
354
368
}
355
369
}
356
370
launch {
357
- nodeParams.feeCredit
358
- .drop(1 ) // we drop the initial value which is 0 sat
359
- .collect { feeCredit -> consoleLog(" fee credit: $feeCredit " ) }
371
+ peer.feeCreditFlow
372
+ .drop(1 ) // we drop the initial value which is 0 msat
373
+ .collect { feeCredit -> consoleLog(" fee credit: ${ feeCredit.truncateToSatoshi()} " ) }
360
374
}
361
375
}
362
376
@@ -370,8 +384,6 @@ class Phoenixd : CliktCommand() {
370
384
371
385
runBlocking {
372
386
peer.connectionState.first { it == Connection .ESTABLISHED }
373
- peer.registerFcmToken(" super-${randomBytes32().toHex()} " )
374
- peer.setAutoLiquidityParams(liquidityOptions.autoLiquidity)
375
387
}
376
388
377
389
val server = embeddedServer(CIO , port = httpBindPort, host = httpBindIp,
0 commit comments