diff --git a/protos/src/lib.rs b/protos/src/lib.rs index bfe1ae4..bd29df4 100644 --- a/protos/src/lib.rs +++ b/protos/src/lib.rs @@ -322,6 +322,202 @@ pub struct ListChannelsResponse { #[prost(message, repeated, tag = "1")] pub channels: ::prost::alloc::vec::Vec, } +/// Returns payment details for a given payment_id. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsRequest { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub payment_id: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPaymentDetailsResponse { + /// Represents a payment. + /// Will be `None` if payment doesn't exist. + #[prost(message, optional, tag = "1")] + pub payment: ::core::option::Option, +} +/// Retrieves list of all payments. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPaymentsResponse { + /// List of payments. + #[prost(message, repeated, tag = "1")] + pub payments: ::prost::alloc::vec::Vec, +} +/// Represents a payment. +/// See more: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Payment { + /// An identifier used to uniquely identify a payment in hex-encoded form. + #[prost(string, tag = "1")] + pub id: ::prost::alloc::string::String, + /// The kind of the payment. + #[prost(message, optional, tag = "2")] + pub kind: ::core::option::Option, + /// The amount transferred. + #[prost(uint64, optional, tag = "3")] + pub amount_msat: ::core::option::Option, + /// The direction of the payment. + #[prost(enumeration = "PaymentDirection", tag = "4")] + pub direction: i32, + /// The status of the payment. + #[prost(enumeration = "PaymentStatus", tag = "5")] + pub status: i32, + /// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + #[prost(uint64, tag = "6")] + pub latest_update_timestamp: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PaymentKind { + #[prost(oneof = "payment_kind::Kind", tags = "1, 2, 3, 4, 5, 6")] + pub kind: ::core::option::Option, +} +/// Nested message and enum types in `PaymentKind`. +pub mod payment_kind { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Kind { + #[prost(message, tag = "1")] + Onchain(super::Onchain), + #[prost(message, tag = "2")] + Bolt11(super::Bolt11), + #[prost(message, tag = "3")] + Bolt11Jit(super::Bolt11Jit), + #[prost(message, tag = "4")] + Bolt12Offer(super::Bolt12Offer), + #[prost(message, tag = "5")] + Bolt12Refund(super::Bolt12Refund), + #[prost(message, tag = "6")] + Spontaneous(super::Spontaneous), + } +} +/// Represents an on-chain payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Onchain {} +/// Represents a BOLT 11 payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11 { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, +} +/// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt11Jit { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// Limits applying to how much fee we allow an LSP to deduct from the payment amount. + /// + /// Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. + /// + /// See \[`LdkChannelConfig::accept_underpaying_htlcs`\]() + /// for more information. + #[prost(message, optional, tag = "4")] + pub lsp_fee_limits: ::core::option::Option, +} +/// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Offer { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The hex-encoded ID of the offer this payment is for. + #[prost(string, tag = "4")] + pub offer_id: ::prost::alloc::string::String, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Bolt12Refund { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, optional, tag = "1")] + pub hash: ::core::option::Option<::prost::alloc::string::String>, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, + /// The secret used by the payment. + #[prost(bytes = "bytes", optional, tag = "3")] + pub secret: ::core::option::Option<::prost::bytes::Bytes>, + /// The payer's note for the payment. + /// Truncated to \[PAYER_NOTE_LIMIT\](). + /// + /// **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + /// all non-printable characters will be sanitized and replaced with safe characters. + #[prost(string, optional, tag = "5")] + pub payer_note: ::core::option::Option<::prost::alloc::string::String>, + /// The quantity of an item requested in the offer. + #[prost(uint64, optional, tag = "6")] + pub quantity: ::core::option::Option, +} +/// Represents a spontaneous (“keysend”) payment. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Spontaneous { + /// The payment hash, i.e., the hash of the preimage. + #[prost(string, tag = "1")] + pub hash: ::prost::alloc::string::String, + /// The pre-image used by the payment. + #[prost(string, optional, tag = "2")] + pub preimage: ::core::option::Option<::prost::alloc::string::String>, +} +/// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +/// See \[`LdkChannelConfig::accept_underpaying_htlcs`\] for more information. +/// +/// \[`LdkChannelConfig::accept_underpaying_htlcs`\]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LspFeeLimits { + /// The maximal total amount we allow any configured LSP withhold from us when forwarding the + /// payment. + #[prost(uint64, optional, tag = "1")] + pub max_total_opening_fee_msat: ::core::option::Option, + /// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + /// LSP withhold from us when forwarding the payment. + #[prost(uint64, optional, tag = "2")] + pub max_proportional_opening_fee_ppm_msat: ::core::option::Option, +} #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Channel { @@ -473,3 +669,65 @@ pub struct BestBlock { #[prost(uint32, tag = "2")] pub height: u32, } +/// Represents the direction of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentDirection { + /// The payment is inbound. + Inbound = 0, + /// The payment is outbound. + Outbound = 1, +} +impl PaymentDirection { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentDirection::Inbound => "INBOUND", + PaymentDirection::Outbound => "OUTBOUND", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "INBOUND" => Some(Self::Inbound), + "OUTBOUND" => Some(Self::Outbound), + _ => None, + } + } +} +/// Represents the current status of a payment. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum PaymentStatus { + /// The payment is still pending. + Pending = 0, + /// The payment succeeded. + Succeeded = 1, + /// The payment failed. + Failed = 2, +} +impl PaymentStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + PaymentStatus::Pending => "PENDING", + PaymentStatus::Succeeded => "SUCCEEDED", + PaymentStatus::Failed => "FAILED", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "PENDING" => Some(Self::Pending), + "SUCCEEDED" => Some(Self::Succeeded), + "FAILED" => Some(Self::Failed), + _ => None, + } + } +} diff --git a/protos/src/proto/ldk_node_server.proto b/protos/src/proto/ldk_node_server.proto index 4d30393..79d935a 100644 --- a/protos/src/proto/ldk_node_server.proto +++ b/protos/src/proto/ldk_node_server.proto @@ -298,6 +298,188 @@ message ListChannelsResponse { repeated Channel channels = 1; } +// Returns payment details for a given payment_id. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.payment +message GetPaymentDetailsRequest { + // An identifier used to uniquely identify a payment in hex-encoded form. + string payment_id = 1; +} + +message GetPaymentDetailsResponse { + // Represents a payment. + // Will be `None` if payment doesn't exist. + Payment payment = 1; +} + +// Retrieves list of all payments. +// See more: https://docs.rs/ldk-node/latest/ldk_node/struct.Node.html#method.list_payments +message ListPaymentsRequest {} + +message ListPaymentsResponse { + // List of payments. + repeated Payment payments = 1; +} + +// Represents a payment. +// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.PaymentDetails.html +message Payment { + // An identifier used to uniquely identify a payment in hex-encoded form. + string id = 1; + + // The kind of the payment. + PaymentKind kind = 2; + + // The amount transferred. + optional uint64 amount_msat = 3; + + // The direction of the payment. + PaymentDirection direction = 4; + + // The status of the payment. + PaymentStatus status = 5; + + // The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated. + uint64 latest_update_timestamp = 6; +} + +message PaymentKind { + oneof kind { + Onchain onchain = 1; + Bolt11 bolt11 = 2; + Bolt11Jit bolt11_jit = 3; + Bolt12Offer bolt12_offer = 4; + Bolt12Refund bolt12_refund = 5; + Spontaneous spontaneous = 6; + } +} + +// Represents an on-chain payment. +message Onchain {} + +// Represents a BOLT 11 payment. +message Bolt11 { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; +} + +// Represents a BOLT 11 payment intended to open an LSPS 2 just-in-time channel. +message Bolt11Jit { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // Limits applying to how much fee we allow an LSP to deduct from the payment amount. + // + // Allowing them to deduct this fee from the first inbound payment will pay for the LSP’s channel opening fees. + // + // See [`LdkChannelConfig::accept_underpaying_htlcs`](https://docs.rs/lightning/latest/lightning/util/config/struct.ChannelConfig.html#structfield.accept_underpaying_htlcs) + // for more information. + LSPFeeLimits lsp_fee_limits = 4; +} + +// Represents a BOLT 12 ‘offer’ payment, i.e., a payment for an Offer. +message Bolt12Offer { + // The payment hash, i.e., the hash of the preimage. + optional string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // The hex-encoded ID of the offer this payment is for. + string offer_id = 4; + + // The payer's note for the payment. + // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). + // + // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + // all non-printable characters will be sanitized and replaced with safe characters. + optional string payer_note = 5; + + // The quantity of an item requested in the offer. + optional uint64 quantity = 6; +} + +// Represents a BOLT 12 ‘refund’ payment, i.e., a payment for a Refund. +message Bolt12Refund { + // The payment hash, i.e., the hash of the preimage. + optional string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; + + // The secret used by the payment. + optional bytes secret = 3; + + // The payer's note for the payment. + // Truncated to [PAYER_NOTE_LIMIT](https://docs.rs/lightning/latest/lightning/offers/invoice_request/constant.PAYER_NOTE_LIMIT.html). + // + // **Caution**: The `payer_note` field may come from an untrusted source. To prevent potential misuse, + // all non-printable characters will be sanitized and replaced with safe characters. + optional string payer_note = 5; + + // The quantity of an item requested in the offer. + optional uint64 quantity = 6; + +} + +// Represents a spontaneous (“keysend”) payment. +message Spontaneous { + // The payment hash, i.e., the hash of the preimage. + string hash = 1; + + // The pre-image used by the payment. + optional string preimage = 2; +} + +// Limits applying to how much fee we allow an LSP to deduct from the payment amount. +// See [`LdkChannelConfig::accept_underpaying_htlcs`] for more information. +// +// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs +message LSPFeeLimits { + // The maximal total amount we allow any configured LSP withhold from us when forwarding the + // payment. + optional uint64 max_total_opening_fee_msat = 1; + + // The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured + // LSP withhold from us when forwarding the payment. + optional uint64 max_proportional_opening_fee_ppm_msat = 2; +} + +// Represents the direction of a payment. +enum PaymentDirection { + // The payment is inbound. + INBOUND = 0; + + // The payment is outbound. + OUTBOUND = 1; +} + +// Represents the current status of a payment. +enum PaymentStatus { + // The payment is still pending. + PENDING = 0; + + // The payment succeeded. + SUCCEEDED = 1; + + // The payment failed. + FAILED = 2; +} + message Channel { // The channel ID (prior to funding transaction generation, this is a random 32-byte // identifier, afterwards this is the transaction ID of the funding transaction XOR the diff --git a/server/src/api/get_payment_details.rs b/server/src/api/get_payment_details.rs new file mode 100644 index 0000000..52008a3 --- /dev/null +++ b/server/src/api/get_payment_details.rs @@ -0,0 +1,23 @@ +use crate::util::proto_adapter::payment_to_proto; +use hex::FromHex; +use ldk_node::lightning::ln::channelmanager::PaymentId; +use ldk_node::Node; +use protos::{GetPaymentDetailsRequest, GetPaymentDetailsResponse}; +use std::sync::Arc; + +pub(crate) const GET_PAYMENT_DETAILS_PATH: &str = "GetPaymentDetails"; + +pub(crate) fn handle_get_payment_details_request( + node: Arc, request: GetPaymentDetailsRequest, +) -> Result { + let payment_id_bytes = <[u8; PaymentId::LENGTH]>::from_hex(&request.payment_id) + .map_err(|_| ldk_node::NodeError::InvalidPaymentId)?; + + let payment_details = node.payment(&PaymentId(payment_id_bytes)); + + let response = GetPaymentDetailsResponse { + payment: payment_details.map(|payment| payment_to_proto(payment)), + }; + + Ok(response) +} diff --git a/server/src/api/list_payments.rs b/server/src/api/list_payments.rs new file mode 100644 index 0000000..2667d58 --- /dev/null +++ b/server/src/api/list_payments.rs @@ -0,0 +1,15 @@ +use crate::util::proto_adapter::payment_to_proto; +use ldk_node::Node; +use protos::{ListPaymentsRequest, ListPaymentsResponse}; +use std::sync::Arc; + +pub(crate) const LIST_PAYMENTS_PATH: &str = "ListPayments"; + +pub(crate) fn handle_list_payments_request( + node: Arc, _request: ListPaymentsRequest, +) -> Result { + let payments = node.list_payments().into_iter().map(|p| payment_to_proto(p)).collect(); + + let response = ListPaymentsResponse { payments }; + Ok(response) +} diff --git a/server/src/api/mod.rs b/server/src/api/mod.rs index 6355e9d..c1079f2 100644 --- a/server/src/api/mod.rs +++ b/server/src/api/mod.rs @@ -4,7 +4,9 @@ pub(crate) mod bolt12_receive; pub(crate) mod bolt12_send; pub(crate) mod close_channel; pub(crate) mod get_node_info; +pub(crate) mod get_payment_details; pub(crate) mod list_channels; +pub(crate) mod list_payments; pub(crate) mod onchain_receive; pub(crate) mod onchain_send; pub(crate) mod open_channel; diff --git a/server/src/service.rs b/server/src/service.rs index 15eaa79..510131d 100644 --- a/server/src/service.rs +++ b/server/src/service.rs @@ -17,7 +17,11 @@ use crate::api::bolt12_receive::{handle_bolt12_receive_request, BOLT12_RECEIVE_P use crate::api::bolt12_send::{handle_bolt12_send_request, BOLT12_SEND_PATH}; use crate::api::close_channel::{handle_close_channel_request, CLOSE_CHANNEL_PATH}; use crate::api::get_node_info::{handle_get_node_info_request, GET_NODE_INFO}; +use crate::api::get_payment_details::{ + handle_get_payment_details_request, GET_PAYMENT_DETAILS_PATH, +}; use crate::api::list_channels::{handle_list_channels_request, LIST_CHANNELS_PATH}; +use crate::api::list_payments::{handle_list_payments_request, LIST_PAYMENTS_PATH}; use crate::api::onchain_receive::{handle_onchain_receive_request, ONCHAIN_RECEIVE_PATH}; use crate::api::onchain_send::{handle_onchain_send_request, ONCHAIN_SEND_PATH}; use crate::api::open_channel::{handle_open_channel, OPEN_CHANNEL_PATH}; @@ -58,6 +62,10 @@ impl Service> for NodeService { OPEN_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_open_channel)), CLOSE_CHANNEL_PATH => Box::pin(handle_request(node, req, handle_close_channel_request)), LIST_CHANNELS_PATH => Box::pin(handle_request(node, req, handle_list_channels_request)), + GET_PAYMENT_DETAILS_PATH => { + Box::pin(handle_request(node, req, handle_get_payment_details_request)) + }, + LIST_PAYMENTS_PATH => Box::pin(handle_request(node, req, handle_list_payments_request)), path => { let error = format!("Unknown request: {}", path).into_bytes(); Box::pin(async { diff --git a/server/src/util/proto_adapter.rs b/server/src/util/proto_adapter.rs index 55d6437..9f9efe7 100644 --- a/server/src/util/proto_adapter.rs +++ b/server/src/util/proto_adapter.rs @@ -1,7 +1,12 @@ +use bytes::Bytes; use hex::prelude::*; use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure}; +use ldk_node::payment::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use ldk_node::ChannelDetails; -use protos::{Channel, OutPoint}; +use protos::payment_kind::Kind::{ + Bolt11, Bolt11Jit, Bolt12Offer, Bolt12Refund, Onchain, Spontaneous, +}; +use protos::{Channel, LspFeeLimits, OutPoint, Payment}; pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { Channel { @@ -61,3 +66,75 @@ pub(crate) fn channel_config_to_proto(channel_config: ChannelConfig) -> protos:: }, } } + +pub(crate) fn payment_to_proto(payment: PaymentDetails) -> Payment { + Payment { + id: payment.id.0.to_lower_hex_string(), + kind: Some(payment_kind_to_proto(payment.kind)), + amount_msat: payment.amount_msat, + direction: match payment.direction { + PaymentDirection::Inbound => protos::PaymentDirection::Inbound.into(), + PaymentDirection::Outbound => protos::PaymentDirection::Outbound.into(), + }, + status: match payment.status { + PaymentStatus::Pending => protos::PaymentStatus::Pending.into(), + PaymentStatus::Succeeded => protos::PaymentStatus::Succeeded.into(), + PaymentStatus::Failed => protos::PaymentStatus::Failed.into(), + }, + latest_update_timestamp: payment.latest_update_timestamp, + } +} + +pub(crate) fn payment_kind_to_proto(payment_kind: PaymentKind) -> protos::PaymentKind { + match payment_kind { + PaymentKind::Onchain => protos::PaymentKind { kind: Some(Onchain(protos::Onchain {})) }, + PaymentKind::Bolt11 { hash, preimage, secret } => protos::PaymentKind { + kind: Some(Bolt11(protos::Bolt11 { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + })), + }, + PaymentKind::Bolt11Jit { hash, preimage, secret, lsp_fee_limits } => protos::PaymentKind { + kind: Some(Bolt11Jit(protos::Bolt11Jit { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + lsp_fee_limits: Some(LspFeeLimits { + max_total_opening_fee_msat: lsp_fee_limits.max_total_opening_fee_msat, + max_proportional_opening_fee_ppm_msat: lsp_fee_limits + .max_proportional_opening_fee_ppm_msat, + }), + })), + }, + PaymentKind::Bolt12Offer { hash, preimage, secret, offer_id, payer_note, quantity } => { + protos::PaymentKind { + kind: Some(Bolt12Offer(protos::Bolt12Offer { + hash: hash.map(|h| h.to_string()), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + offer_id: offer_id.0.to_lower_hex_string(), + payer_note: payer_note.map(|s| s.to_string()), + quantity, + })), + } + }, + PaymentKind::Bolt12Refund { hash, preimage, secret, payer_note, quantity } => { + protos::PaymentKind { + kind: Some(Bolt12Refund(protos::Bolt12Refund { + hash: hash.map(|h| h.to_string()), + preimage: preimage.map(|p| p.to_string()), + secret: secret.map(|s| Bytes::copy_from_slice(&s.0)), + payer_note: payer_note.map(|s| s.to_string()), + quantity, + })), + } + }, + PaymentKind::Spontaneous { hash, preimage } => protos::PaymentKind { + kind: Some(Spontaneous(protos::Spontaneous { + hash: hash.to_string(), + preimage: preimage.map(|p| p.to_string()), + })), + }, + } +}