Skip to content

Commit

Permalink
fixes breez#598
Browse files Browse the repository at this point in the history
  • Loading branch information
vacwmX committed Nov 14, 2023
1 parent fb9b267 commit d8cb18b
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 81 deletions.
6 changes: 5 additions & 1 deletion libs/sdk-core/src/greenlight/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ impl From<tonic::Status> for NodeError {
JsonRpcErrCode::InvoiceNoDescription => Self::InvoiceNoDescription(status.into()),
JsonRpcErrCode::InvoicePreimageAlreadyExists => {
Self::InvoicePreimageAlreadyExists(status.into())
}
},
JsonRpcErrCode::OfferExpired => Self::OfferExpired(status.into()),
JsonRpcErrCode::OfferBadInvreqReply => Self::OfferReplyError(status.into()),
JsonRpcErrCode::OfferRouteNotFound => Self::RouteNotFound(status.into()),
JsonRpcErrCode::OfferTimeout => Self::OfferTimeout(status.into()),
_ => Self::Generic(status.into()),
},
_ => Self::Generic(status.into()),
Expand Down
59 changes: 27 additions & 32 deletions libs/sdk-core/src/greenlight/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use strum_macros::{Display, EnumString};
use tokio::sync::{mpsc, Mutex};
use tokio::time::sleep;
use tokio_stream::{Stream, StreamExt};
use tonic::{Code, Streaming};
use tonic::Streaming;

use crate::invoice::{parse_invoice, InvoiceError, RouteHintHop};
use crate::models::*;
Expand Down Expand Up @@ -1313,43 +1313,38 @@ impl NodeAPI for Greenlight {
#[allow(unused_variables)]
async fn fetch_invoice(
&self,
offer: String,
amount_msat: Option<u64>,
quantity: Option<u64>,
recurrence_counter: Option<u64>,
recurrence_start: Option<f64>,
recurrence_label: Option<String>,
timeout: Option<f64>,
payer_note: Option<String>,
req: FetchInvoiceRequest
) -> NodeResult<FetchInvoiceResponse> {
// Get the required pubkeys
let mut client = self.get_node_client().await?;

// Parse the offer locally, to avoid any unnecessary calls to the recipient
if let Err(parse_error) = offer.parse::<Offer>() {
return Err(NodeError::Generic(anyhow!("Invalid offer")));
if let Err(parse_error) = req.offer.parse::<Offer>() {
return Err(NodeError::InvalidOffer(parse_error));
}

let mut client = self.get_node_client().await?;
let response = client
.fetch_invoice(cln::FetchinvoiceRequest {
offer,
amount_msat: amount_msat.map(|msat| cln::Amount { msat }),
quantity,
recurrence_counter,
recurrence_start,
recurrence_label,
timeout,
payer_note,
})
.await;
.fetch_invoice(Into::<cln::FetchinvoiceRequest>::into(req))
.await?
.into_inner();

response
.map(|grpc_response| grpc_response.into())
.map_err(|status| match status.code() {
Code::NotFound => NodeError::RouteNotFound(anyhow!(status.message().to_string())),
Code::Unimplemented => NodeError::NotSupported(),
_ => NodeError::Generic(anyhow!("Could not fetch invoice")),
})
Ok(
FetchInvoiceResponse {
invoice: response.invoice,
changes: response.changes.map(|changes| FetchInvoiceChanges {
description: changes.description,
description_appended: changes.description_appended,
vendor: changes.vendor,
vendor_removed: changes.vendor_removed,
amount_msat: changes.amount_msat.map(|amount| amount.msat),
}),
next_period: response.next_period.map(|np| FetchInvoiceNextPeriod {
counter: np.counter,
start_time: np.starttime,
end_time: np.endtime,
paywindow_start: np.paywindow_start,
paywindow_end: np.paywindow_end,
}),
}
)
}
}

Expand Down
11 changes: 2 additions & 9 deletions libs/sdk-core/src/input_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use anyhow::{anyhow, Result};
use bip21::Uri;
use bitcoin::bech32;
use bitcoin::bech32::FromBase32;
use lightning::offers::offer::Amount;
use lightning::offers::offer::Offer;
use serde::Deserialize;
use serde::Serialize;
Expand Down Expand Up @@ -179,15 +178,9 @@ pub async fn parse(input: &str) -> Result<InputType> {
return Ok(Bolt12Offer {
offer: LNOffer {
chains: offer.chains(),
amount_msats: offer.amount().map(|amount| {
match amount {
Amount::Currency { amount, .. } => amount,
Amount::Bitcoin { amount_msats } => amount_msats,
}
.clone()
}),
amount: offer.amount().map(|amount| amount.clone().into()),
description: offer.description().to_string(),
absolute_expiry: offer.absolute_expiry(),
absolute_expiry: offer.absolute_expiry().map(|expiry| expiry.as_secs()),
issuer: offer.issuer().map(|s| s.to_string()),
supported_quantity: offer.supported_quantity().into(),
signing_pubkey: offer.signing_pubkey(),
Expand Down
21 changes: 18 additions & 3 deletions libs/sdk-core/src/invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use regex::Regex;
use serde::{Deserialize, Serialize};
use std::num::NonZeroU64;
use std::str::FromStr;
use std::time::{Duration, SystemTimeError, UNIX_EPOCH};
use std::time::{SystemTimeError, UNIX_EPOCH};

pub type InvoiceResult<T, E = InvoiceError> = Result<T, E>;

Expand Down Expand Up @@ -75,12 +75,27 @@ impl From<lightning::offers::offer::Quantity> for Quantity {
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum Amount {
Bitcoin { amount_msats: u64 },
Currency { iso4217_code: [u8; 3], amount: u64 },
}

impl From<lightning::offers::offer::Amount> for Amount {
fn from(amount: lightning::offers::offer::Amount) -> Self {
match amount {
lightning::offers::offer::Amount::Bitcoin { amount_msats } => Amount::Bitcoin { amount_msats },
lightning::offers::offer::Amount::Currency { iso4217_code, amount } => Amount::Currency { iso4217_code, amount },
}
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct LNOffer {
pub chains: Vec<ChainHash>,
pub amount_msats: Option<u64>,
pub amount: Option<Amount>,
pub description: String,
pub absolute_expiry: Option<Duration>,
pub absolute_expiry: Option<u64>,
pub issuer: Option<String>,
pub supported_quantity: Quantity,
pub signing_pubkey: PublicKey,
Expand Down
55 changes: 32 additions & 23 deletions libs/sdk-core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,34 @@ pub struct RefundResponse {
pub refund_tx_id: String,
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct FetchInvoiceRequest {
pub offer: String,
pub amount_msat: Option<u64>,
pub quantity: Option<u64>,
pub timeout: Option<f64>,
pub payer_note: Option<String>,
// pub recurrence_counter: Option<u64>,
// pub recurrence_start: Option<f64>,
// pub recurrence_label: Option<String>,
}

impl Into<gl_client::pb::cln::FetchinvoiceRequest> for FetchInvoiceRequest {
fn into(self) -> gl_client::pb::cln::FetchinvoiceRequest {
gl_client::pb::cln::FetchinvoiceRequest {
offer: self.offer,
amount_msat: self.amount_msat.map(|msat| cln::Amount { msat }),
quantity: self.quantity,
timeout: self.timeout,
payer_note: self.payer_note,
// Not yet implemented
recurrence_counter: None,
recurrence_start: None,
recurrence_label: None,
}
}
}

#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct FetchInvoiceChanges {
pub description_appended: Option<String>,
Expand All @@ -868,8 +896,8 @@ pub struct FetchInvoiceChanges {
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct FetchInvoiceNextPeriod {
pub counter: u64,
pub starttime: u64,
pub endtime: u64,
pub start_time: u64,
pub end_time: u64,
pub paywindow_start: u64,
pub paywindow_end: u64,
}
Expand All @@ -881,27 +909,8 @@ pub struct FetchInvoiceResponse {
pub next_period: Option<FetchInvoiceNextPeriod>,
}

impl From<tonic::Response<cln::FetchinvoiceResponse>> for FetchInvoiceResponse {
fn from(response: tonic::Response<cln::FetchinvoiceResponse>) -> Self {
let response = response.into_inner();

FetchInvoiceResponse {
invoice: response.invoice,
changes: response.changes.map(|changes| FetchInvoiceChanges {
description: changes.description,
description_appended: changes.description_appended,
vendor: changes.vendor,
vendor_removed: changes.vendor_removed,
amount_msat: changes.amount_msat.map(|amount| amount.msat),
}),
next_period: response.next_period.map(|np| FetchInvoiceNextPeriod {
counter: np.counter,
starttime: np.starttime,
endtime: np.endtime,
paywindow_start: np.paywindow_start,
paywindow_end: np.paywindow_end,
}),
}
impl From<cln::FetchinvoiceResponse> for FetchInvoiceResponse {
fn from(response: cln::FetchinvoiceResponse) -> Self {
}
}

Expand Down
28 changes: 15 additions & 13 deletions libs/sdk-core/src/node_api.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{
invoice::InvoiceError, persist::error::PersistError, CustomMessage, MaxChannelAmount,
NodeCredentials, PaymentResponse, Peer, PrepareSweepRequest, PrepareSweepResponse,
RouteHintHop, SyncResponse,
invoice::InvoiceError, persist::error::PersistError, CustomMessage, FetchInvoiceResponse,
PaymentResponse, Peer, PrepareSweepRequest, PrepareSweepResponse, SyncResponse, FetchInvoiceRequest,
};
use anyhow::Result;
use bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey};
use lightning::offers::parse::ParseError;
use lightning_invoice::RawInvoice;
use std::pin::Pin;
use tokio::sync::mpsc;
Expand Down Expand Up @@ -48,8 +48,17 @@ pub enum NodeError {
#[error("Service connectivity: {0}")]
ServiceConnectivity(anyhow::Error),

#[error("Feature not yet supported by Greenlight")]
NotSupported(),
#[error("Invalid offer: {0:?}")]
InvalidOffer(ParseError),

#[error("Offer expired: {0}")]
OfferExpired(anyhow::Error),

#[error("Offer reply error: {0}")]
OfferReplyError(anyhow::Error),

#[error("Offer timeout: {0}")]
OfferTimeout(anyhow::Error),
}

/// Trait covering functions affecting the LN node
Expand Down Expand Up @@ -119,14 +128,7 @@ pub trait NodeAPI: Send + Sync {
) -> NodeResult<Pin<Box<dyn Stream<Item = Result<CustomMessage>> + Send>>>;
async fn fetch_invoice(
&self,
offer: String,
amount_msat: Option<u64>,
quantity: Option<u64>,
recurrence_counter: Option<u64>,
recurrence_start: Option<f64>,
recurrence_label: Option<String>,
timeout: Option<f64>,
payer_note: Option<String>,
req: FetchInvoiceRequest,
) -> NodeResult<FetchInvoiceResponse>;

/// Gets the private key at the path specified
Expand Down

0 comments on commit d8cb18b

Please sign in to comment.