From c2f8a87d2d827ad82d689cb12b5622259ff1c72a Mon Sep 17 00:00:00 2001 From: Restioson Date: Mon, 4 Sep 2023 18:22:56 +0200 Subject: [PATCH] feat: model lightning payment fees --- .../down.sql | 2 ++ .../up.sql | 4 +++ coordinator/src/db/payments.rs | 16 ++++++++++++ coordinator/src/node/storage.rs | 3 +++ coordinator/src/schema.rs | 1 + crates/ln-dlc-node/src/ldk_node_wallet.rs | 1 + crates/ln-dlc-node/src/lib.rs | 2 ++ crates/ln-dlc-node/src/ln/common_handlers.rs | 4 +++ crates/ln-dlc-node/src/node/invoice.rs | 1 + crates/ln-dlc-node/src/node/storage.rs | 8 ++++++ crates/ln-dlc-node/src/node/wallet.rs | 7 ++++-- .../wallet/domain/wallet_history.dart | 3 +++ .../features/wallet/wallet_history_item.dart | 4 +++ .../down.sql | 2 ++ .../up.sql | 4 +++ mobile/native/src/api.rs | 1 + mobile/native/src/db/mod.rs | 2 ++ mobile/native/src/db/models.rs | 25 +++++++++++++++++++ mobile/native/src/ln_dlc/mod.rs | 1 + mobile/native/src/ln_dlc/node.rs | 11 +++++++- mobile/native/src/schema.rs | 1 + 21 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 coordinator/migrations/2023-09-04-155338_add-fee-to-payments/down.sql create mode 100644 coordinator/migrations/2023-09-04-155338_add-fee-to-payments/up.sql create mode 100644 mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/down.sql create mode 100644 mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/up.sql diff --git a/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/down.sql b/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/down.sql new file mode 100644 index 000000000..44bc2a573 --- /dev/null +++ b/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/down.sql @@ -0,0 +1,2 @@ +ALTER TABLE + payments DROP COLUMN fee_msat; diff --git a/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/up.sql b/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/up.sql new file mode 100644 index 000000000..5c414c470 --- /dev/null +++ b/coordinator/migrations/2023-09-04-155338_add-fee-to-payments/up.sql @@ -0,0 +1,4 @@ +ALTER TABLE + payments +ADD + COLUMN fee_msat BIGINT DEFAULT null; diff --git a/coordinator/src/db/payments.rs b/coordinator/src/db/payments.rs index fa500bf99..6a0094bd1 100644 --- a/coordinator/src/db/payments.rs +++ b/coordinator/src/db/payments.rs @@ -30,6 +30,7 @@ pub struct Payment { pub updated_at: OffsetDateTime, pub description: String, pub invoice: Option, + pub fee_msat: Option, } pub fn get( @@ -114,6 +115,7 @@ impl TryFrom for (lightning::ln::PaymentHash, ln_dlc_node::PaymentInfo) let amt_msat = ln_dlc_node::MillisatAmount::new(value.amount_msat.map(|amount| amount as u64)); + let fee_msat = ln_dlc_node::MillisatAmount::new(value.fee_msat.map(|amount| amount as u64)); Ok(( payment_hash, @@ -122,6 +124,7 @@ impl TryFrom for (lightning::ln::PaymentHash, ln_dlc_node::PaymentInfo) secret, status: value.htlc_status.into(), amt_msat, + fee_msat, flow: value.flow.into(), timestamp: value.payment_timestamp, description: value.description, @@ -240,6 +243,7 @@ pub fn update( payment_hash: lightning::ln::PaymentHash, htlc_status: ln_dlc_node::HTLCStatus, amount_msat: ln_dlc_node::MillisatAmount, + fee_msat: ln_dlc_node::MillisatAmount, preimage: Option, secret: Option, conn: &mut PgConnection, @@ -252,6 +256,7 @@ pub fn update( let payment_hash = payment_hash.0.to_hex(); let htlc_status: HtlcStatus = htlc_status.into(); let amount_msat = amount_msat.to_inner().map(|amt| amt as i64); + let fee_msat = fee_msat.to_inner().map(|amt| amt as i64); conn.transaction::<(), _, _>(|conn| { let affected_rows = diesel::update(payments::table) @@ -274,6 +279,17 @@ pub fn update( } } + if let Some(fee_msat) = fee_msat { + let affected_rows = diesel::update(payments::table) + .filter(schema::payments::payment_hash.eq(&payment_hash)) + .set(schema::payments::fee_msat.eq(fee_msat)) + .execute(conn)?; + + if affected_rows == 0 { + bail!("Could not update payment fee amount") + } + } + if let Some(preimage) = preimage { let affected_rows = diesel::update(payments::table) .filter(schema::payments::payment_hash.eq(&payment_hash)) diff --git a/coordinator/src/node/storage.rs b/coordinator/src/node/storage.rs index b740d39df..a46eb1d15 100644 --- a/coordinator/src/node/storage.rs +++ b/coordinator/src/node/storage.rs @@ -44,6 +44,7 @@ impl node::Storage for NodeStorage { payment_hash: &PaymentHash, flow: PaymentFlow, amt_msat: MillisatAmount, + fee_msat: MillisatAmount, htlc_status: HTLCStatus, preimage: Option, secret: Option, @@ -56,6 +57,7 @@ impl node::Storage for NodeStorage { *payment_hash, htlc_status, amt_msat, + fee_msat, preimage, secret, &mut conn, @@ -70,6 +72,7 @@ impl node::Storage for NodeStorage { secret, status: htlc_status, amt_msat, + fee_msat, flow, timestamp: OffsetDateTime::now_utc(), description: "".to_string(), diff --git a/coordinator/src/schema.rs b/coordinator/src/schema.rs index 4401d9a11..4c6c823b7 100644 --- a/coordinator/src/schema.rs +++ b/coordinator/src/schema.rs @@ -86,6 +86,7 @@ diesel::table! { updated_at -> Timestamptz, description -> Text, invoice -> Nullable, + fee_msat -> Nullable, } } diff --git a/crates/ln-dlc-node/src/ldk_node_wallet.rs b/crates/ln-dlc-node/src/ldk_node_wallet.rs index 73522b15d..647d49495 100644 --- a/crates/ln-dlc-node/src/ldk_node_wallet.rs +++ b/crates/ln-dlc-node/src/ldk_node_wallet.rs @@ -481,6 +481,7 @@ pub mod tests { _payment_hash: &lightning::ln::PaymentHash, _flow: crate::PaymentFlow, _amt_msat: crate::MillisatAmount, + _fee_msat: crate::MillisatAmount, _htlc_status: crate::HTLCStatus, _preimage: Option, _secret: Option, diff --git a/crates/ln-dlc-node/src/lib.rs b/crates/ln-dlc-node/src/lib.rs index 17b8bc3f5..6a3c40162 100644 --- a/crates/ln-dlc-node/src/lib.rs +++ b/crates/ln-dlc-node/src/lib.rs @@ -96,6 +96,7 @@ pub struct PaymentInfo { pub secret: Option, pub status: HTLCStatus, pub amt_msat: MillisatAmount, + pub fee_msat: MillisatAmount, pub flow: PaymentFlow, pub timestamp: OffsetDateTime, pub description: String, @@ -137,6 +138,7 @@ impl From for PaymentInfo { secret: Some(*value.payment_secret()), status: HTLCStatus::Pending, amt_msat: MillisatAmount(value.amount_milli_satoshis()), + fee_msat: MillisatAmount(None), flow: PaymentFlow::Inbound, timestamp: OffsetDateTime::from(value.timestamp()), description: match value.description() { diff --git a/crates/ln-dlc-node/src/ln/common_handlers.rs b/crates/ln-dlc-node/src/ln/common_handlers.rs index 1c2f1b506..a3220676c 100644 --- a/crates/ln-dlc-node/src/ln/common_handlers.rs +++ b/crates/ln-dlc-node/src/ln/common_handlers.rs @@ -164,6 +164,7 @@ where &payment_hash, PaymentFlow::Outbound, amount_msat, + MillisatAmount(fee_paid_msat), HTLCStatus::Succeeded, Some(payment_preimage), None, @@ -186,6 +187,7 @@ where secret: None, status: HTLCStatus::Succeeded, amt_msat, + fee_msat: MillisatAmount(fee_paid_msat), flow: PaymentFlow::Outbound, timestamp: OffsetDateTime::now_utc(), description: "".to_string(), @@ -334,6 +336,7 @@ pub fn handle_payment_claimed( &payment_hash, PaymentFlow::Inbound, amount_msat, + MillisatAmount(None), HTLCStatus::Succeeded, payment_preimage, payment_secret, @@ -359,6 +362,7 @@ where &payment_hash, PaymentFlow::Outbound, amount_msat, + MillisatAmount(None), HTLCStatus::Failed, None, None, diff --git a/crates/ln-dlc-node/src/node/invoice.rs b/crates/ln-dlc-node/src/node/invoice.rs index 116967563..c9fb1892d 100644 --- a/crates/ln-dlc-node/src/node/invoice.rs +++ b/crates/ln-dlc-node/src/node/invoice.rs @@ -225,6 +225,7 @@ where secret: None, status, amt_msat: MillisatAmount(invoice.amount_milli_satoshis()), + fee_msat: MillisatAmount(None), flow: PaymentFlow::Outbound, timestamp: OffsetDateTime::now_utc(), description, diff --git a/crates/ln-dlc-node/src/node/storage.rs b/crates/ln-dlc-node/src/node/storage.rs index 695ffc28b..4d569d3c1 100644 --- a/crates/ln-dlc-node/src/node/storage.rs +++ b/crates/ln-dlc-node/src/node/storage.rs @@ -29,11 +29,13 @@ pub trait Storage { /// Add a new payment. fn insert_payment(&self, payment_hash: PaymentHash, info: PaymentInfo) -> Result<()>; /// Add a new payment or update an existing one. + #[allow(clippy::too_many_arguments)] fn merge_payment( &self, payment_hash: &PaymentHash, flow: PaymentFlow, amt_msat: MillisatAmount, + fee_msat: MillisatAmount, htlc_status: HTLCStatus, preimage: Option, secret: Option, @@ -116,6 +118,7 @@ impl Storage for InMemoryStore { payment_hash: &PaymentHash, flow: PaymentFlow, amt_msat: MillisatAmount, + fee_msat: MillisatAmount, htlc_status: HTLCStatus, preimage: Option, secret: Option, @@ -129,6 +132,10 @@ impl Storage for InMemoryStore { payment.amt_msat = amt_msat } + if let fee_msat @ MillisatAmount(Some(_)) = fee_msat { + payment.fee_msat = fee_msat + } + if let Some(preimage) = preimage { payment.preimage = Some(preimage); } @@ -145,6 +152,7 @@ impl Storage for InMemoryStore { secret, status: htlc_status, amt_msat: MillisatAmount(None), + fee_msat, flow, timestamp: OffsetDateTime::now_utc(), description: "".to_string(), diff --git a/crates/ln-dlc-node/src/node/wallet.rs b/crates/ln-dlc-node/src/node/wallet.rs index 583dbd844..63fe24a7f 100644 --- a/crates/ln-dlc-node/src/node/wallet.rs +++ b/crates/ln-dlc-node/src/node/wallet.rs @@ -151,6 +151,7 @@ where status: info.status, flow: info.flow, amount_msat: info.amt_msat.0, + fee_msat: info.fee_msat.0, timestamp: info.timestamp, description: info.description.clone(), preimage: info.preimage.map(|preimage| preimage.0.to_hex()), @@ -170,6 +171,7 @@ pub struct PaymentDetails { pub status: HTLCStatus, pub flow: PaymentFlow, pub amount_msat: Option, + pub fee_msat: Option, pub timestamp: OffsetDateTime, pub description: String, pub preimage: Option, @@ -182,14 +184,15 @@ impl fmt::Display for PaymentDetails { let status = self.status.to_string(); let flow = self.flow; let amount_msat = self.amount_msat.unwrap_or_default(); + let fee_msat = self.fee_msat.unwrap_or_default(); let timestamp = self.timestamp.to_string(); let description = self.description.clone(); let invoice = self.invoice.clone(); write!( f, - "payment_hash {}, status {}, flow {}, amount_msat {}, timestamp {}, description {} invoice {:?}", - payment_hash, status, flow, amount_msat, timestamp, description, invoice + "payment_hash {}, status {}, flow {}, amount_msat {}, fee_msat {}, timestamp {}, description {}, invoice {:?}", + payment_hash, status, flow, amount_msat, fee_msat, timestamp, description, invoice ) } } diff --git a/mobile/lib/features/wallet/domain/wallet_history.dart b/mobile/lib/features/wallet/domain/wallet_history.dart index 49edb041e..b29f64f9a 100644 --- a/mobile/lib/features/wallet/domain/wallet_history.dart +++ b/mobile/lib/features/wallet/domain/wallet_history.dart @@ -92,6 +92,7 @@ abstract class WalletHistoryItemData { preimage: type.paymentPreimage, description: type.description, paymentHash: type.paymentHash, + feeMsats: type.feeMsat, expiry: expiry, invoice: type.invoice); } @@ -103,6 +104,7 @@ class LightningPaymentData extends WalletHistoryItemData { final String description; final String? invoice; final DateTime? expiry; + final int? feeMsats; LightningPaymentData( {required super.flow, @@ -113,6 +115,7 @@ class LightningPaymentData extends WalletHistoryItemData { required this.description, required this.invoice, required this.expiry, + required this.feeMsats, required this.paymentHash}); @override diff --git a/mobile/lib/features/wallet/wallet_history_item.dart b/mobile/lib/features/wallet/wallet_history_item.dart index 1f59e122a..6d6abdfb4 100644 --- a/mobile/lib/features/wallet/wallet_history_item.dart +++ b/mobile/lib/features/wallet/wallet_history_item.dart @@ -167,6 +167,10 @@ class LightningPaymentHistoryItem extends WalletHistoryItem { @override List getDetails() { return [ + Visibility( + visible: data.feeMsats != null, + child: HistoryDetail(label: "Fee", value: "${(data.feeMsats ?? 0) / 1000} sats"), + ), Visibility( visible: data.expiry != null, child: HistoryDetail( diff --git a/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/down.sql b/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/down.sql new file mode 100644 index 000000000..44bc2a573 --- /dev/null +++ b/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/down.sql @@ -0,0 +1,2 @@ +ALTER TABLE + payments DROP COLUMN fee_msat; diff --git a/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/up.sql b/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/up.sql new file mode 100644 index 000000000..5c414c470 --- /dev/null +++ b/mobile/native/migrations/2023-09-04-155338_add-fee-to-payments/up.sql @@ -0,0 +1,4 @@ +ALTER TABLE + payments +ADD + COLUMN fee_msat BIGINT DEFAULT null; diff --git a/mobile/native/src/api.rs b/mobile/native/src/api.rs index 788d38151..781cf50c0 100644 --- a/mobile/native/src/api.rs +++ b/mobile/native/src/api.rs @@ -85,6 +85,7 @@ pub enum WalletHistoryItemType { description: String, payment_preimage: Option, invoice: Option, + fee_msat: Option, expiry_timestamp: Option, }, Trade { diff --git a/mobile/native/src/db/mod.rs b/mobile/native/src/db/mod.rs index 67f7d22f9..84527abf8 100644 --- a/mobile/native/src/db/mod.rs +++ b/mobile/native/src/db/mod.rs @@ -271,6 +271,7 @@ pub fn update_payment( payment_hash: lightning::ln::PaymentHash, htlc_status: ln_dlc_node::HTLCStatus, amt_msat: ln_dlc_node::MillisatAmount, + fee_msat: ln_dlc_node::MillisatAmount, preimage: Option, secret: Option, ) -> Result<()> { @@ -287,6 +288,7 @@ pub fn update_payment( base64.encode(payment_hash.0), htlc_status.into(), amt_msat.to_inner().map(|amt| amt as i64), + fee_msat.to_inner().map(|amt| amt as i64), preimage, secret, &mut db, diff --git a/mobile/native/src/db/models.rs b/mobile/native/src/db/models.rs index 57094ace7..0e837a49a 100644 --- a/mobile/native/src/db/models.rs +++ b/mobile/native/src/db/models.rs @@ -667,6 +667,8 @@ pub(crate) struct PaymentInsertable { pub htlc_status: HtlcStatus, #[diesel(sql_type = Nullable)] pub amount_msat: Option, + #[diesel(sql_type = Nullable)] + pub fee_msat: Option, pub flow: Flow, pub created_at: i64, pub updated_at: i64, @@ -706,6 +708,7 @@ impl PaymentInsertable { payment_hash: String, htlc_status: HtlcStatus, amount_msat: Option, + fee_msat: Option, preimage: Option, secret: Option, conn: &mut SqliteConnection, @@ -733,6 +736,17 @@ impl PaymentInsertable { } } + if let Some(fee_msat) = fee_msat { + let affected_rows = diesel::update(payments::table) + .filter(schema::payments::payment_hash.eq(&payment_hash)) + .set(schema::payments::fee_msat.eq(fee_msat)) + .execute(conn)?; + + if affected_rows == 0 { + bail!("Could not update payment fee amount") + } + } + if let Some(preimage) = preimage { let affected_rows = diesel::update(payments::table) .filter(schema::payments::payment_hash.eq(&payment_hash)) @@ -785,6 +799,7 @@ pub(crate) struct PaymentQueryable { pub updated_at: i64, pub description: String, pub invoice: Option, + pub fee_msat: Option, } impl PaymentQueryable { @@ -811,6 +826,7 @@ impl From<(lightning::ln::PaymentHash, ln_dlc_node::PaymentInfo)> for PaymentIns secret: info.secret.map(|secret| base64.encode(secret.0)), htlc_status: info.status.into(), amount_msat: info.amt_msat.to_inner().map(|amt| amt as i64), + fee_msat: info.fee_msat.to_inner().map(|amt| amt as i64), flow: info.flow.into(), created_at: timestamp, updated_at: timestamp, @@ -860,6 +876,7 @@ impl TryFrom for (lightning::ln::PaymentHash, ln_dlc_node::Pay let amt_msat = ln_dlc_node::MillisatAmount::new(value.amount_msat.map(|amount| amount as u64)); + let fee_msat = ln_dlc_node::MillisatAmount::new(value.fee_msat.map(|amount| amount as u64)); let flow = value.flow.into(); @@ -875,6 +892,7 @@ impl TryFrom for (lightning::ln::PaymentHash, ln_dlc_node::Pay secret, status, amt_msat, + fee_msat, flow, timestamp, description, @@ -1473,6 +1491,7 @@ pub mod test { let secret = None; let htlc_status = HtlcStatus::Pending; let amount_msat = Some(10_000_000); + let fee_msat = Some(120); let flow = Flow::Inbound; let created_at = 100; let updated_at = 100; @@ -1485,6 +1504,7 @@ pub mod test { secret: secret.clone(), htlc_status, amount_msat, + fee_msat, flow, created_at, updated_at, @@ -1502,6 +1522,7 @@ pub mod test { secret: None, htlc_status: HtlcStatus::Pending, amount_msat: None, + fee_msat: None, flow: Flow::Outbound, created_at: 200, updated_at: 200, @@ -1523,6 +1544,7 @@ pub mod test { secret, htlc_status, amount_msat, + fee_msat, flow, created_at, updated_at, @@ -1537,12 +1559,14 @@ pub mod test { let new_htlc_status = HtlcStatus::Succeeded; let preimage = Some("preimage".to_string()); let amount_msat = Some(1_000_000); + let fee_msat = Some(150); let secret = Some("secret".to_string()); let updated_at = PaymentInsertable::update( payment_hash.to_string(), new_htlc_status, amount_msat, + fee_msat, preimage.clone(), secret.clone(), &mut connection, @@ -1557,6 +1581,7 @@ pub mod test { secret, htlc_status: new_htlc_status, amount_msat, + fee_msat, updated_at, ..expected_payment }; diff --git a/mobile/native/src/ln_dlc/mod.rs b/mobile/native/src/ln_dlc/mod.rs index 4435a4598..bbc351dd0 100644 --- a/mobile/native/src/ln_dlc/mod.rs +++ b/mobile/native/src/ln_dlc/mod.rs @@ -405,6 +405,7 @@ fn keep_wallet_balance_and_history_up_to_date(node: &Node) -> Result<()> { description: details.description.clone(), payment_preimage: details.preimage.clone(), invoice: details.invoice.clone(), + fee_msat: details.fee_msat, expiry_timestamp, } }; diff --git a/mobile/native/src/ln_dlc/node.rs b/mobile/native/src/ln_dlc/node.rs index 98edd1280..53d6b5b76 100644 --- a/mobile/native/src/ln_dlc/node.rs +++ b/mobile/native/src/ln_dlc/node.rs @@ -398,13 +398,21 @@ impl node::Storage for NodeStorage { payment_hash: &PaymentHash, flow: PaymentFlow, amt_msat: MillisatAmount, + fee_msat: MillisatAmount, htlc_status: HTLCStatus, preimage: Option, secret: Option, ) -> Result<()> { match db::get_payment(*payment_hash)? { Some(_) => { - db::update_payment(*payment_hash, htlc_status, amt_msat, preimage, secret)?; + db::update_payment( + *payment_hash, + htlc_status, + amt_msat, + fee_msat, + preimage, + secret, + )?; } None => { db::insert_payment( @@ -414,6 +422,7 @@ impl node::Storage for NodeStorage { secret, status: htlc_status, amt_msat, + fee_msat, flow, timestamp: OffsetDateTime::now_utc(), description: "".to_string(), diff --git a/mobile/native/src/schema.rs b/mobile/native/src/schema.rs index b5180cf5b..c65902860 100644 --- a/mobile/native/src/schema.rs +++ b/mobile/native/src/schema.rs @@ -51,6 +51,7 @@ diesel::table! { updated_at -> BigInt, description -> Text, invoice -> Nullable, + fee_msat -> Nullable, } }