diff --git a/src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt b/src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt index 925e38b1c..098b225ed 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt @@ -23,8 +23,8 @@ sealed interface SwapInEvents : NodeEvents { data class Requested(val walletInputs: List) : SwapInEvents { val totalAmount: Satoshi = walletInputs.map { it.amount }.sum() } - data class Accepted(val inputs: Set, val amount: Satoshi, val fees: ChannelManagementFees) : SwapInEvents { - val receivedAmount: Satoshi = amount - fees.total + data class Accepted(val inputs: Set, val amountBeforeFees: Satoshi, val fees: ChannelManagementFees) : SwapInEvents { + val receivedAmount: Satoshi = amountBeforeFees - fees.total } } @@ -35,7 +35,7 @@ sealed interface ChannelEvents : NodeEvents { } sealed interface LiquidityEvents : NodeEvents { - /** Amount of the liquidity event, before fees are paid. */ + /** Amount of liquidity purchased, before fees are paid. */ val amount: MilliSatoshi val fee: MilliSatoshi val source: Source @@ -74,7 +74,7 @@ data object UpgradeRequired : NodeEvents sealed interface PaymentEvents : NodeEvents { data class PaymentReceived(val paymentHash: ByteVector32, val receivedWith: List) : PaymentEvents { - val amount: MilliSatoshi = receivedWith.map { it.amount }.sum() + val amount: MilliSatoshi = receivedWith.map { it.amountReceived }.sum() val fees: MilliSatoshi = receivedWith.map { it.fees }.sum() } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt index d2f919eeb..e7bb9be6f 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelAction.kt @@ -9,6 +9,7 @@ import fr.acinq.lightning.channel.states.PersistedChannelState import fr.acinq.lightning.db.ChannelClosingType import fr.acinq.lightning.transactions.Transactions import fr.acinq.lightning.utils.UUID +import fr.acinq.lightning.utils.toMilliSatoshi import fr.acinq.lightning.wire.* /** Channel Actions (outputs produced by the state machine). */ @@ -78,8 +79,8 @@ sealed class ChannelAction { abstract val origin: Origin? abstract val txId: TxId abstract val localInputs: Set - data class ViaNewChannel(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin?) : StoreIncomingPayment() - data class ViaSpliceIn(val amount: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin?) : StoreIncomingPayment() + data class ViaNewChannel(val amountReceived: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin?) : StoreIncomingPayment() + data class ViaSpliceIn(val amountReceived: MilliSatoshi, val serviceFee: MilliSatoshi, val miningFee: Satoshi, override val localInputs: Set, override val txId: TxId, override val origin: Origin?) : StoreIncomingPayment() } /** Payment sent through on-chain operations (channel close or splice-out) */ sealed class StoreOutgoingPayment : Storage() { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelData.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelData.kt index e4f7984b7..62f3eabd9 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelData.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelData.kt @@ -12,6 +12,7 @@ import fr.acinq.lightning.crypto.KeyManager import fr.acinq.lightning.logging.LoggingContext import fr.acinq.lightning.transactions.Scripts import fr.acinq.lightning.transactions.Transactions.TransactionWithInputInfo.* +import fr.acinq.lightning.utils.toMilliSatoshi import fr.acinq.lightning.wire.ClosingSigned /** @@ -410,12 +411,14 @@ data class ChannelManagementFees(val miningFee: Satoshi, val serviceFee: Satoshi // @formatter:off sealed class Origin { /** Amount of the origin payment, before fees are paid. */ - abstract val amount: MilliSatoshi + abstract val amountBeforeFees: MilliSatoshi /** Fees applied for the channel funding transaction. */ abstract val fees: ChannelManagementFees - data class OnChainWallet(val inputs: Set, override val amount: MilliSatoshi, override val fees: ChannelManagementFees) : Origin() - data class OffChainPayment(val paymentPreimage: ByteVector32, override val amount: MilliSatoshi, override val fees: ChannelManagementFees) : Origin() { + fun amountReceived(): MilliSatoshi = amountBeforeFees - fees.total.toMilliSatoshi() + + data class OnChainWallet(val inputs: Set, override val amountBeforeFees: MilliSatoshi, override val fees: ChannelManagementFees) : Origin() + data class OffChainPayment(val paymentPreimage: ByteVector32, override val amountBeforeFees: MilliSatoshi, override val fees: ChannelManagementFees) : Origin() { val paymentHash: ByteVector32 = Crypto.sha256(paymentPreimage).byteVector32() } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt index 66cb9eb4d..f2c98a21a 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/Normal.kt @@ -888,7 +888,7 @@ data class Normal( // If we received or sent funds as part of the splice, we will add a corresponding entry to our incoming/outgoing payments db addAll(origins.map { origin -> ChannelAction.Storage.StoreIncomingPayment.ViaSpliceIn( - amount = origin.amount, + amountReceived = origin.amountReceived(), serviceFee = origin.fees.serviceFee.toMilliSatoshi(), miningFee = origin.fees.miningFee, localInputs = action.fundingTx.sharedTx.tx.localInputs.map { it.outPoint }.toSet(), @@ -899,7 +899,7 @@ data class Normal( // If we added some funds ourselves it's a swap-in if (action.fundingTx.sharedTx.tx.localInputs.isNotEmpty()) add( ChannelAction.Storage.StoreIncomingPayment.ViaSpliceIn( - amount = action.fundingTx.sharedTx.tx.localInputs.map { i -> i.txOut.amount }.sum().toMilliSatoshi() - action.fundingTx.sharedTx.tx.localFees, + amountReceived = action.fundingTx.sharedTx.tx.localInputs.map { i -> i.txOut.amount }.sum().toMilliSatoshi() - action.fundingTx.sharedTx.tx.localFees, serviceFee = 0.msat, miningFee = action.fundingTx.sharedTx.tx.localFees.truncateToSatoshi(), localInputs = action.fundingTx.sharedTx.tx.localInputs.map { it.outPoint }.toSet(), @@ -927,8 +927,8 @@ data class Normal( } addAll(origins.map { origin -> when (origin) { - is Origin.OffChainPayment -> ChannelAction.EmitEvent(LiquidityEvents.Accepted(origin.amount, origin.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment)) - is Origin.OnChainWallet -> ChannelAction.EmitEvent(SwapInEvents.Accepted(origin.inputs, origin.amount.truncateToSatoshi(), origin.fees)) + is Origin.OffChainPayment -> ChannelAction.EmitEvent(LiquidityEvents.Accepted(liquidityPurchase?.amount?.toMilliSatoshi() ?: 0.msat, origin.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment)) + is Origin.OnChainWallet -> ChannelAction.EmitEvent(SwapInEvents.Accepted(origin.inputs, origin.amountBeforeFees.truncateToSatoshi(), origin.fees)) } }) if (staticParams.useZeroConf) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt index c80bc3d81..0e32e026c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSigned.kt @@ -122,7 +122,7 @@ data class WaitForFundingSigned( // If we receive funds as part of the channel creation, we will add it to our payments db if (action.commitment.localCommit.spec.toLocal > 0.msat) add( ChannelAction.Storage.StoreIncomingPayment.ViaNewChannel( - amount = action.commitment.localCommit.spec.toLocal, + amountReceived = action.commitment.localCommit.spec.toLocal, serviceFee = channelOrigin?.fees?.serviceFee?.toMilliSatoshi() ?: 0.msat, miningFee = channelOrigin?.fees?.miningFee ?: action.fundingTx.sharedTx.tx.localFees.truncateToSatoshi(), localInputs = action.fundingTx.sharedTx.tx.localInputs.map { it.outPoint }.toSet(), @@ -140,8 +140,8 @@ data class WaitForFundingSigned( } channelOrigin?.let { when (it) { - is Origin.OffChainPayment -> add(ChannelAction.EmitEvent(LiquidityEvents.Accepted(it.amount, it.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment))) - is Origin.OnChainWallet -> add(ChannelAction.EmitEvent(SwapInEvents.Accepted(it.inputs, it.amount.truncateToSatoshi(), it.fees))) + is Origin.OffChainPayment -> add(ChannelAction.EmitEvent(LiquidityEvents.Accepted(liquidityPurchase?.amount?.toMilliSatoshi() ?: 0.msat, it.fees.total.toMilliSatoshi(), LiquidityEvents.Source.OffChainPayment))) + is Origin.OnChainWallet -> add(ChannelAction.EmitEvent(SwapInEvents.Accepted(it.inputs, it.amountBeforeFees.truncateToSatoshi(), it.fees))) } } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt b/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt index dc0fb48fd..411dc372e 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/db/PaymentsDb.kt @@ -156,7 +156,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r data class Received(val receivedWith: List, val receivedAt: Long = currentTimestampMillis()) { /** Total amount received after applying the fees. */ - val amount: MilliSatoshi = receivedWith.map { it.amount }.sum() + val amount: MilliSatoshi = receivedWith.map { it.amountReceived }.sum() /** Fees applied to receive this payment. */ val fees: MilliSatoshi = receivedWith.map { it.fees }.sum() @@ -164,13 +164,13 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r sealed class ReceivedWith { /** Amount received for this part after applying the fees. This is the final amount we can use. */ - abstract val amount: MilliSatoshi + abstract val amountReceived: MilliSatoshi /** Fees applied to receive this part. Is zero for Lightning payments. */ abstract val fees: MilliSatoshi /** Payment was received via existing lightning channels. */ - data class LightningPayment(override val amount: MilliSatoshi, val channelId: ByteVector32, val htlcId: Long, val fundingFee: LiquidityAds.FundingFee?) : ReceivedWith() { + data class LightningPayment(override val amountReceived: MilliSatoshi, val channelId: ByteVector32, val htlcId: Long, val fundingFee: LiquidityAds.FundingFee?) : ReceivedWith() { // If there is no funding fee, the fees are paid by the sender for lightning payments. override val fees: MilliSatoshi = fundingFee?.amount ?: 0.msat } @@ -188,13 +188,13 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r /** * Payment was received via a new channel opened to us. * - * @param amount Our side of the balance of this channel when it's created. This is the amount pushed to us once the creation fees are applied. + * @param amountReceived Our side of the balance of this channel when it's created. This is the amount received after the creation fees are applied. * @param serviceFee Fees paid to Lightning Service Provider to open this channel. * @param miningFee Feed paid to bitcoin miners for processing the L1 transaction. * @param channelId The long id of the channel created to receive this payment. May be null if the channel id is not known. */ data class NewChannel( - override val amount: MilliSatoshi, + override val amountReceived: MilliSatoshi, override val serviceFee: MilliSatoshi, override val miningFee: Satoshi, override val channelId: ByteVector32, @@ -204,7 +204,7 @@ data class IncomingPayment(val preimage: ByteVector32, val origin: Origin, val r ) : OnChainIncomingPayment() data class SpliceIn( - override val amount: MilliSatoshi, + override val amountReceived: MilliSatoshi, override val serviceFee: MilliSatoshi, override val miningFee: Satoshi, override val channelId: ByteVector32, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandler.kt b/src/commonMain/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandler.kt index d45feb332..cddff9717 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandler.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandler.kt @@ -109,7 +109,7 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: PaymentsDb, pri val receivedWith = when (action) { is ChannelAction.Storage.StoreIncomingPayment.ViaNewChannel -> IncomingPayment.ReceivedWith.NewChannel( - amount = action.amount, + amountReceived = action.amountReceived, serviceFee = action.serviceFee, miningFee = action.miningFee, channelId = channelId, @@ -119,7 +119,7 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: PaymentsDb, pri ) is ChannelAction.Storage.StoreIncomingPayment.ViaSpliceIn -> IncomingPayment.ReceivedWith.SpliceIn( - amount = action.amount, + amountReceived = action.amountReceived, serviceFee = action.serviceFee, miningFee = action.miningFee, channelId = channelId, diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt index 494314312..a0d4c40a1 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Deserialization.kt @@ -482,12 +482,12 @@ object Deserialization { } 0x03 -> Origin.OffChainPayment( paymentPreimage = readByteVector32(), - amount = readNumber().msat, + amountBeforeFees = readNumber().msat, fees = ChannelManagementFees(miningFee = readNumber().sat, serviceFee = readNumber().sat), ) 0x04 -> Origin.OnChainWallet( inputs = readCollection { readOutPoint() }.toSet(), - amount = readNumber().msat, + amountBeforeFees = readNumber().msat, fees = ChannelManagementFees(miningFee = readNumber().sat, serviceFee = readNumber().sat), ) else -> error("unknown discriminator $discriminator for class ${Origin::class}") diff --git a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt index 9dac84ef3..6261412d8 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/serialization/v4/Serialization.kt @@ -455,14 +455,14 @@ object Serialization { is Origin.OffChainPayment -> { write(0x03) writeByteVector32(o.paymentPreimage) - writeNumber(o.amount.toLong()) + writeNumber(o.amountBeforeFees.toLong()) writeNumber(o.fees.miningFee.toLong()) writeNumber(o.fees.serviceFee.toLong()) } is Origin.OnChainWallet -> { write(0x04) writeCollection(o.inputs) { writeBtcObject(it) } - writeNumber(o.amount.toLong()) + writeNumber(o.amountBeforeFees.toLong()) writeNumber(o.fees.miningFee.toLong()) writeNumber(o.fees.serviceFee.toLong()) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt index b95cfbe0b..8e1faa7a5 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingSignedTestsCommon.kt @@ -36,7 +36,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { assertEquals(actions.size, 5) actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } actions.findWatch().also { assertEquals(WatchConfirmed(state.channelId, commitInput.outPoint.txid, commitInput.txOut.publicKeyScript, 3, BITCOIN_FUNDING_DEPTHOK), it) } - actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi() + TestConstants.alicePushAmount - TestConstants.bobPushAmount, it.amount) } + actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi() + TestConstants.alicePushAmount - TestConstants.bobPushAmount, it.amountReceived) } actions.has() actions.find().also { assertEquals(ChannelEvents.Created(state.state), it.event) } } @@ -59,7 +59,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } actions.hasOutgoingMessage().also { assertEquals(ShortChannelId.peerId(bob.staticParams.nodeParams.nodeId), it.alias) } actions.findWatch().also { assertEquals(state.commitments.latest.fundingTxId, it.txId) } - actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi() + TestConstants.alicePushAmount - TestConstants.bobPushAmount, it.amount) } + actions.find().also { assertEquals(TestConstants.bobFundingAmount.toMilliSatoshi() + TestConstants.alicePushAmount - TestConstants.bobPushAmount, it.amountReceived) } actions.has() actions.find().also { assertEquals(ChannelEvents.Created(state.state), it.event) } } @@ -87,7 +87,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { assertEquals(TestConstants.aliceFundingAmount - purchase.fees.total, state.commitments.latest.localCommit.spec.toRemote.truncateToSatoshi()) actions.hasOutgoingMessage().also { assertFalse(it.channelData.isEmpty()) } actions.findWatch().also { assertEquals(BITCOIN_FUNDING_DEPTHOK, it.event) } - actions.find().also { assertEquals((TestConstants.bobFundingAmount + purchase.fees.total).toMilliSatoshi(), it.amount) } + actions.find().also { assertEquals((TestConstants.bobFundingAmount + purchase.fees.total).toMilliSatoshi(), it.amountReceived) } actions.has() actions.find().also { assertEquals(ChannelEvents.Created(state.state), it.event) } } @@ -103,7 +103,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { actionsAlice1.hasOutgoingMessage() actionsAlice1.has() actionsAlice1.find().also { - assertEquals(50_000_000.msat, it.amount) + assertEquals(50_000_000.msat, it.amountReceived) assertEquals(channelOrigin, it.origin) assertEquals(alice1.commitments.latest.fundingTxId, it.txId) } @@ -123,7 +123,7 @@ class WaitForFundingSignedTestsCommon : LightningTestSuite() { actionsAlice1.hasOutgoingMessage() actionsAlice1.has() actionsAlice1.find().also { - assertEquals(it.amount, 200_000_000.msat) + assertEquals(it.amountReceived, 200_000_000.msat) assertEquals(it.origin, channelOrigin) assertTrue(it.localInputs.isNotEmpty()) } diff --git a/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt index fc805d27f..356cadace 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/db/PaymentsDbTestsCommon.kt @@ -57,7 +57,7 @@ class PaymentsDbTestsCommon : LightningTestSuite() { assertEquals(100_000.msat, received.amount) assertEquals(0.msat, received.fees) assertEquals(2, received.received!!.receivedWith.size) - assertEquals(57_000.msat, received.received!!.receivedWith.elementAt(0).amount) + assertEquals(57_000.msat, received.received!!.receivedWith.elementAt(0).amountReceived) assertEquals(0.msat, received.received!!.receivedWith.elementAt(0).fees) assertEquals(channelId1, (received.received!!.receivedWith.elementAt(0) as IncomingPayment.ReceivedWith.LightningPayment).channelId) assertEquals(54, (received.received!!.receivedWith.elementAt(1) as IncomingPayment.ReceivedWith.LightningPayment).htlcId) diff --git a/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt index 51b6224f1..88a5be758 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/payment/IncomingPaymentHandlerTestsCommon.kt @@ -1267,7 +1267,7 @@ class IncomingPaymentHandlerTestsCommon : LightningTestSuite() { paidInvoice.paymentHash, receivedWith = listOf( IncomingPayment.ReceivedWith.NewChannel( - amount = 15_000_000.msat, + amountReceived = 15_000_000.msat, serviceFee = 1_000_000.msat, miningFee = 0.sat, channelId = randomBytes32(),