diff --git a/libs/Cargo.lock b/libs/Cargo.lock index 55df7e4d4..8f9902687 100644 --- a/libs/Cargo.lock +++ b/libs/Cargo.lock @@ -572,7 +572,6 @@ dependencies = [ "tokio", "tokio-stream", "tonic", - "tonic-build", "zbase32", ] @@ -2798,6 +2797,7 @@ dependencies = [ "log", "mockito", "once_cell", + "prost", "querystring", "regex", "reqwest", @@ -2807,6 +2807,8 @@ dependencies = [ "strum_macros", "thiserror", "tokio", + "tonic", + "tonic-build", ] [[package]] diff --git a/libs/Cargo.toml b/libs/Cargo.toml index 78d04355b..61f4c893c 100644 --- a/libs/Cargo.toml +++ b/libs/Cargo.toml @@ -28,6 +28,7 @@ lightning-invoice = "=0.24.0" # Same version as used in gl-client log = "0.4" mockito = "1" once_cell = "1" +prost = "^0.11" regex = "1.8.1" reqwest = { version = "=0.11.20", features = ["json"] } rusqlite = { version = "0.29", features = [ @@ -43,5 +44,7 @@ strum = "0.25" strum_macros = "0.25" thiserror = "1.0.56" tokio = { version = "1", features = ["full"] } +tonic = "^0.8" +tonic-build = "^0.8" uniffi = "0.23.0" uniffi_macros = "0.23.0" diff --git a/libs/sdk-bindings/Cargo.toml b/libs/sdk-bindings/Cargo.toml index 775462620..2402c3b24 100644 --- a/libs/sdk-bindings/Cargo.toml +++ b/libs/sdk-bindings/Cargo.toml @@ -28,7 +28,7 @@ log = { workspace = true } once_cell = { workspace = true } flutter_rust_bridge = "=1.82.6" tiny-bip39 = "*" -tonic = { version = "^0.8", features = [ +tonic = { workspace = true, features = [ "tls", "tls-roots", "tls-webpki-roots", diff --git a/libs/sdk-common/Cargo.toml b/libs/sdk-common/Cargo.toml index e1a8b1d6d..d8e50bd60 100644 --- a/libs/sdk-common/Cargo.toml +++ b/libs/sdk-common/Cargo.toml @@ -15,6 +15,7 @@ lightning = { workspace = true } lightning-invoice = { workspace = true } log = { workspace = true } querystring = "1" +prost = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } rusqlite = { workspace = true } @@ -22,9 +23,13 @@ serde = { workspace = true } serde_json = { workspace = true } strum_macros = { workspace = true } thiserror = { workspace = true } +tonic = { workspace = true } [dev-dependencies] bitcoin = { workspace = true, features = ["rand"] } mockito = { workspace = true } tokio = { workspace = true } -once_cell = { workspace = true } \ No newline at end of file +once_cell = { workspace = true } + +[build-dependencies] +tonic-build = { workspace = true } \ No newline at end of file diff --git a/libs/sdk-common/build.rs b/libs/sdk-common/build.rs new file mode 100644 index 000000000..bc809bb88 --- /dev/null +++ b/libs/sdk-common/build.rs @@ -0,0 +1,4 @@ +fn main() -> Result<(), Box> { + tonic_build::compile_protos("src/grpc/proto/breez.proto")?; + Ok(()) +} diff --git a/libs/sdk-common/src/breez_server.rs b/libs/sdk-common/src/breez_server.rs new file mode 100644 index 000000000..4ae3987aa --- /dev/null +++ b/libs/sdk-common/src/breez_server.rs @@ -0,0 +1,139 @@ +use anyhow::Result; +use log::trace; +use tonic::codegen::InterceptedService; +use tonic::metadata::errors::InvalidMetadataValue; +use tonic::metadata::{Ascii, MetadataValue}; +use tonic::service::Interceptor; +use tonic::transport::{Channel, Endpoint}; +use tonic::{Request, Status}; + +use crate::grpc::channel_opener_client::ChannelOpenerClient; +use crate::grpc::information_client::InformationClient; +use crate::grpc::payment_notifier_client::PaymentNotifierClient; +use crate::grpc::signer_client::SignerClient; +use crate::grpc::support_client::SupportClient; +use crate::grpc::swapper_client::SwapperClient; +use crate::grpc::{ChainApiServersRequest, PingRequest}; +use crate::prelude::ServiceConnectivityError; + +pub struct BreezServer { + grpc_channel: Channel, + api_key: Option, +} + +impl BreezServer { + pub fn new(server_url: String, api_key: Option) -> Result { + Ok(Self { + grpc_channel: Endpoint::from_shared(server_url)?.connect_lazy(), + api_key, + }) + } + + fn api_key_metadata(&self) -> Result>, ServiceConnectivityError> { + match &self.api_key { + Some(key) => Ok(Some(format!("Bearer {key}").parse().map_err( + |e: InvalidMetadataValue| { + ServiceConnectivityError::new(&format!( + "(Breez: {:?}) Failed parse API key: {e}", + self.api_key + )) + }, + )?)), + _ => Ok(None), + } + } + + pub async fn get_channel_opener_client( + &self, + ) -> Result< + ChannelOpenerClient>, + ServiceConnectivityError, + > { + let api_key_metadata = self.api_key_metadata()?; + let with_interceptor = ChannelOpenerClient::with_interceptor( + self.grpc_channel.clone(), + ApiKeyInterceptor { api_key_metadata }, + ); + Ok(with_interceptor) + } + + pub async fn get_payment_notifier_client(&self) -> PaymentNotifierClient { + PaymentNotifierClient::new(self.grpc_channel.clone()) + } + + pub async fn get_information_client(&self) -> InformationClient { + InformationClient::new(self.grpc_channel.clone()) + } + + pub async fn get_signer_client(&self) -> SignerClient { + SignerClient::new(self.grpc_channel.clone()) + } + + pub async fn get_support_client( + &self, + ) -> Result< + SupportClient>, + ServiceConnectivityError, + > { + let api_key_metadata = self.api_key_metadata()?; + Ok(SupportClient::with_interceptor( + self.grpc_channel.clone(), + ApiKeyInterceptor { api_key_metadata }, + )) + } + + pub async fn get_swapper_client(&self) -> SwapperClient { + SwapperClient::new(self.grpc_channel.clone()) + } + + pub async fn ping(&self) -> Result { + let request = Request::new(PingRequest {}); + let response = self + .get_information_client() + .await + .ping(request) + .await? + .into_inner() + .version; + Ok(response) + } + + pub async fn fetch_mempoolspace_urls(&self) -> Result, ServiceConnectivityError> { + let mut client = self.get_information_client().await; + + let chain_api_servers = client + .chain_api_servers(ChainApiServersRequest {}) + .await + .map_err(|e| { + ServiceConnectivityError::new(&format!( + "(Breez: {e:?}) Failed to fetch ChainApiServers" + )) + })? + .into_inner() + .servers; + trace!("Received chain_api_servers: {chain_api_servers:?}"); + + let mempoolspace_urls = chain_api_servers + .iter() + .filter(|s| s.server_type == "MEMPOOL_SPACE") + .map(|s| s.server_base_url.clone()) + .collect(); + trace!("Received mempoolspace_urls: {mempoolspace_urls:?}"); + + Ok(mempoolspace_urls) + } +} + +pub struct ApiKeyInterceptor { + api_key_metadata: Option>, +} + +impl Interceptor for ApiKeyInterceptor { + fn call(&mut self, mut req: Request<()>) -> Result, Status> { + if self.api_key_metadata.clone().is_some() { + req.metadata_mut() + .insert("authorization", self.api_key_metadata.clone().unwrap()); + } + Ok(req) + } +} diff --git a/libs/sdk-common/src/error.rs b/libs/sdk-common/src/error.rs new file mode 100644 index 000000000..24bfcfb56 --- /dev/null +++ b/libs/sdk-common/src/error.rs @@ -0,0 +1,21 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +#[error("{err}")] +pub struct ServiceConnectivityError { + pub err: String, +} +impl ServiceConnectivityError { + pub fn new(err: &str) -> Self { + ServiceConnectivityError { + err: err.to_string(), + } + } +} +impl From for ServiceConnectivityError { + fn from(err: reqwest::Error) -> Self { + Self { + err: err.to_string(), + } + } +} diff --git a/libs/sdk-core/src/grpc/mod.rs b/libs/sdk-common/src/grpc/mod.rs similarity index 100% rename from libs/sdk-core/src/grpc/mod.rs rename to libs/sdk-common/src/grpc/mod.rs diff --git a/libs/sdk-core/src/grpc/proto/breez.proto b/libs/sdk-common/src/grpc/proto/breez.proto similarity index 100% rename from libs/sdk-core/src/grpc/proto/breez.proto rename to libs/sdk-common/src/grpc/proto/breez.proto diff --git a/libs/sdk-common/src/lib.rs b/libs/sdk-common/src/lib.rs index 4d6ee94bc..4df28434b 100644 --- a/libs/sdk-common/src/lib.rs +++ b/libs/sdk-common/src/lib.rs @@ -1,12 +1,18 @@ +mod breez_server; +mod error; +pub mod grpc; pub mod input_parser; pub mod invoice; mod lnurl; mod model; mod utils; +// We don't include grpc::* in the prelude exports, to force callers to use the grpc path prefix. #[rustfmt::skip] pub mod prelude { pub use crate::*; + pub use crate::breez_server::*; + pub use crate::error::*; pub use crate::input_parser::*; pub use crate::invoice::*; pub use crate::lnurl::error::*; diff --git a/libs/sdk-common/src/utils/rest_client.rs b/libs/sdk-common/src/utils/rest_client.rs index 09e1ebdcd..ddf9d54cf 100644 --- a/libs/sdk-common/src/utils/rest_client.rs +++ b/libs/sdk-common/src/utils/rest_client.rs @@ -2,25 +2,8 @@ use std::time::Duration; use log::*; use reqwest::StatusCode; -use thiserror::Error; -#[derive(Debug, Error)] -#[error("{err}")] -pub struct ServiceConnectivityError { - pub err: String, -} -impl ServiceConnectivityError { - pub fn new(err: String) -> Self { - ServiceConnectivityError { err } - } -} -impl From for ServiceConnectivityError { - fn from(err: reqwest::Error) -> Self { - Self { - err: err.to_string(), - } - } -} +use crate::error::ServiceConnectivityError; /// Creates an HTTP client with a built-in connection timeout pub fn get_reqwest_client() -> Result { @@ -83,8 +66,8 @@ where if enforce_status_check && !status.is_success() { let err = format!("GET request {url} failed with status: {status}"); error!("{err}"); - return Err(ServiceConnectivityError::new(err)); + return Err(ServiceConnectivityError::new(&err)); } - serde_json::from_str::(&raw_body).map_err(|e| ServiceConnectivityError::new(e.to_string())) + serde_json::from_str::(&raw_body).map_err(|e| ServiceConnectivityError::new(&e.to_string())) } diff --git a/libs/sdk-core/Cargo.toml b/libs/sdk-core/Cargo.toml index c3a8dceee..21488aa9c 100644 --- a/libs/sdk-core/Cargo.toml +++ b/libs/sdk-core/Cargo.toml @@ -27,14 +27,14 @@ ripemd = "0.1" rand = "0.8" tiny-bip39 = "1" tokio = { workspace = true } -prost = "^0.11" +prost = { workspace = true } rusqlite = { workspace = true } rusqlite_migration = "1.0" reqwest = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sdk-common = { path = "../sdk-common" } -tonic = { version = "^0.8", features = [ +tonic = { workspace = true, features = [ "tls", "transport", "tls-roots", @@ -57,5 +57,3 @@ regex = { workspace = true } [dev-dependencies] mockito = { workspace = true } -[build-dependencies] -tonic-build = "^0.8" diff --git a/libs/sdk-core/build.rs b/libs/sdk-core/build.rs index f6d432278..8a03e3a9c 100644 --- a/libs/sdk-core/build.rs +++ b/libs/sdk-core/build.rs @@ -1,5 +1,4 @@ fn main() -> Result<(), Box> { - tonic_build::compile_protos("src/grpc/proto/breez.proto")?; set_git_revision_hash(); Ok(()) } diff --git a/libs/sdk-core/src/breez_services.rs b/libs/sdk-core/src/breez_services.rs index 4fef1916f..a141bb11e 100644 --- a/libs/sdk-core/src/breez_services.rs +++ b/libs/sdk-core/src/breez_services.rs @@ -15,16 +15,11 @@ use futures::TryFutureExt; use gl_client::bitcoin::secp256k1::Secp256k1; use log::{LevelFilter, Metadata, Record}; use reqwest::{header::CONTENT_TYPE, Body, Url}; +use sdk_common::grpc; use sdk_common::prelude::*; use serde_json::json; use tokio::sync::{mpsc, watch, Mutex}; use tokio::time::{sleep, MissedTickBehavior}; -use tonic::codegen::InterceptedService; -use tonic::metadata::errors::InvalidMetadataValue; -use tonic::metadata::{Ascii, MetadataValue}; -use tonic::service::Interceptor; -use tonic::transport::{Channel, Endpoint}; -use tonic::{Request, Status}; use crate::backup::{BackupRequest, BackupTransport, BackupWatcher}; use crate::chain::{ @@ -37,13 +32,6 @@ use crate::error::{ }; use crate::fiat::{FiatCurrency, Rate}; use crate::greenlight::{GLBackupTransport, Greenlight}; -use crate::grpc::channel_opener_client::ChannelOpenerClient; -use crate::grpc::information_client::InformationClient; -use crate::grpc::payment_notifier_client::PaymentNotifierClient; -use crate::grpc::signer_client::SignerClient; -use crate::grpc::support_client::SupportClient; -use crate::grpc::swapper_client::SwapperClient; -use crate::grpc::{ChainApiServersRequest, PaymentInformation}; use crate::lnurl::pay::*; use crate::lsp::LspInformation; use crate::models::{ @@ -60,8 +48,6 @@ use crate::swap_out::reverseswap::{BTCSendSwap, CreateReverseSwapArg}; use crate::BuyBitcoinProvider::Moonpay; use crate::*; -use self::grpc::PingRequest; - pub type BreezServicesResult = Result; /// Trait that can be used to react to various [BreezEvent]s emitted by the SDK. @@ -2308,116 +2294,6 @@ impl BreezServicesBuilder { } } -pub struct BreezServer { - grpc_channel: Channel, - api_key: Option, -} - -impl BreezServer { - pub fn new(server_url: String, api_key: Option) -> Result { - Ok(Self { - grpc_channel: Endpoint::from_shared(server_url)?.connect_lazy(), - api_key, - }) - } - - fn api_key_metadata(&self) -> SdkResult>> { - match &self.api_key { - Some(key) => Ok(Some(format!("Bearer {key}").parse().map_err( - |e: InvalidMetadataValue| SdkError::ServiceConnectivity { - err: format!("(Breez: {:?}) Failed parse API key: {e}", self.api_key), - }, - )?)), - _ => Ok(None), - } - } - - pub(crate) async fn get_channel_opener_client( - &self, - ) -> SdkResult>> { - let api_key_metadata = self.api_key_metadata()?; - let with_interceptor = ChannelOpenerClient::with_interceptor( - self.grpc_channel.clone(), - ApiKeyInterceptor { api_key_metadata }, - ); - Ok(with_interceptor) - } - - pub(crate) async fn get_payment_notifier_client( - &self, - ) -> SdkResult> { - Ok(PaymentNotifierClient::new(self.grpc_channel.clone())) - } - - pub(crate) async fn get_information_client(&self) -> SdkResult> { - Ok(InformationClient::new(self.grpc_channel.clone())) - } - - pub(crate) async fn get_signer_client(&self) -> SdkResult> { - Ok(SignerClient::new(self.grpc_channel.clone())) - } - - pub(crate) async fn get_support_client( - &self, - ) -> SdkResult>> { - let api_key_metadata = self.api_key_metadata()?; - Ok(SupportClient::with_interceptor( - self.grpc_channel.clone(), - ApiKeyInterceptor { api_key_metadata }, - )) - } - - pub(crate) async fn get_swapper_client(&self) -> SdkResult> { - Ok(SwapperClient::new(self.grpc_channel.clone())) - } - - pub(crate) async fn ping(&self) -> SdkResult { - let request = Request::new(PingRequest {}); - let response = self - .get_information_client() - .await? - .ping(request) - .await? - .into_inner() - .version; - Ok(response) - } - - pub(crate) async fn fetch_mempoolspace_urls(&self) -> SdkResult> { - let mut client = self.get_information_client().await?; - - let chain_api_servers = client - .chain_api_servers(ChainApiServersRequest {}) - .await? - .into_inner() - .servers; - trace!("Received chain_api_servers: {chain_api_servers:?}"); - - let mempoolspace_urls = chain_api_servers - .iter() - .filter(|s| s.server_type == "MEMPOOL_SPACE") - .map(|s| s.server_base_url.clone()) - .collect(); - trace!("Received mempoolspace_urls: {mempoolspace_urls:?}"); - - Ok(mempoolspace_urls) - } -} - -pub(crate) struct ApiKeyInterceptor { - api_key_metadata: Option>, -} - -impl Interceptor for ApiKeyInterceptor { - fn call(&mut self, mut req: Request<()>) -> Result, Status> { - if self.api_key_metadata.clone().is_some() { - req.metadata_mut() - .insert("authorization", self.api_key_metadata.clone().unwrap()); - } - Ok(req) - } -} - /// Attempts to convert the phrase to a mnemonic, then to a seed. /// /// If the phrase is not a valid mnemonic, an error is returned. @@ -2429,7 +2305,7 @@ pub fn mnemonic_to_seed(phrase: String) -> Result> { pub struct OpenChannelParams { pub payer_amount_msat: u64, - pub opening_fee_params: OpeningFeeParams, + pub opening_fee_params: models::OpeningFeeParams, } #[tonic::async_trait] @@ -2655,7 +2531,7 @@ impl PaymentReceiver { .register_payment( lsp_info.id.clone(), lsp_info.lsp_pubkey.clone(), - PaymentInformation { + grpc::PaymentInformation { payment_hash: hex::decode(parsed_invoice.payment_hash.clone()) .map_err(|e| anyhow!("Failed to decode hex payment hash: {e}"))?, payment_secret: parsed_invoice.payment_secret.clone(), diff --git a/libs/sdk-core/src/fiat.rs b/libs/sdk-core/src/fiat.rs index 21aee023b..cc32fd358 100644 --- a/libs/sdk-core/src/fiat.rs +++ b/libs/sdk-core/src/fiat.rs @@ -1,12 +1,13 @@ use std::collections::HashMap; -use crate::error::SdkResult; -use crate::grpc::RatesRequest; -use crate::models::FiatAPI; -use crate::{breez_services::BreezServer, error::SdkError}; use serde::{Deserialize, Serialize}; +use sdk_common::prelude::BreezServer; +use sdk_common::grpc::RatesRequest; use tonic::Request; +use crate::error::{SdkError, SdkResult}; +use crate::models::FiatAPI; + /// Settings for the symbol representation of a currency #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Symbol { @@ -84,7 +85,7 @@ impl FiatAPI for BreezServer { } async fn fetch_fiat_rates(&self) -> SdkResult> { - let mut client = self.get_information_client().await?; + let mut client = self.get_information_client().await; let request = Request::new(RatesRequest {}); let response = client diff --git a/libs/sdk-core/src/greenlight/node_api.rs b/libs/sdk-core/src/greenlight/node_api.rs index b49cf9298..2208291a8 100644 --- a/libs/sdk-core/src/greenlight/node_api.rs +++ b/libs/sdk-core/src/greenlight/node_api.rs @@ -51,9 +51,7 @@ use crate::lightning_invoice::{RawBolt11Invoice, SignedRawBolt11Invoice}; use crate::node_api::{CreateInvoiceRequest, FetchBolt11Result, NodeAPI, NodeError, NodeResult}; use crate::persist::db::SqliteStorage; use crate::{models::*, LspInformation}; -use crate::{ - NodeConfig, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, RouteHint, -}; +use crate::{NodeConfig, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse}; const MAX_PAYMENT_AMOUNT_MSAT: u64 = 4294967000; const MAX_INBOUND_LIQUIDITY_MSAT: u64 = 4000000000; diff --git a/libs/sdk-core/src/lib.rs b/libs/sdk-core/src/lib.rs index db51b0407..8236ea901 100644 --- a/libs/sdk-core/src/lib.rs +++ b/libs/sdk-core/src/lib.rs @@ -170,10 +170,6 @@ pub mod error; #[rustfmt::skip] mod node_api; // flutter_rust_bridge_codegen: has to be defined before greenlight; greenlight::node_api mod greenlight; -// GRPC structs are documented as follows: -// - if they are mirrored in Rust model structs, documented in the model structs -// - if there is no corresponding model struct, documented in breez.proto -mod grpc; #[rustfmt::skip] mod fiat; // flutter_rust_bridge_codegen: has to be defined after grpc; grpc::Rate pub mod lnurl; diff --git a/libs/sdk-core/src/lsp.rs b/libs/sdk-core/src/lsp.rs index c4edd7fd8..73793eb23 100644 --- a/libs/sdk-core/src/lsp.rs +++ b/libs/sdk-core/src/lsp.rs @@ -1,16 +1,16 @@ -use crate::breez_services::BreezServer; use crate::crypt::encrypt; use crate::error::{SdkError, SdkResult}; -use crate::grpc::{ +use crate::models::{LspAPI, OpeningFeeParams, OpeningFeeParamsMenu}; + +use anyhow::{anyhow, Result}; +use prost::Message; +use sdk_common::grpc::{ self, LspListRequest, PaymentInformation, RegisterPaymentNotificationRequest, RegisterPaymentNotificationResponse, RegisterPaymentReply, RegisterPaymentRequest, RemovePaymentNotificationRequest, RemovePaymentNotificationResponse, SubscribeNotificationsRequest, UnsubscribeNotificationsRequest, }; -use crate::models::{LspAPI, OpeningFeeParams, OpeningFeeParamsMenu}; - -use anyhow::{anyhow, Result}; -use prost::Message; +use sdk_common::prelude::BreezServer; use serde::{Deserialize, Serialize}; use tonic::Request; @@ -120,7 +120,7 @@ impl LspAPI for BreezServer { signature: webhook_url_signature, }; - let mut client = self.get_payment_notifier_client().await?; + let mut client = self.get_payment_notifier_client().await; let mut buf = Vec::with_capacity(subscribe_request.encoded_len()); subscribe_request @@ -150,7 +150,7 @@ impl LspAPI for BreezServer { signature: webhook_url_signature, }; - let mut client = self.get_payment_notifier_client().await?; + let mut client = self.get_payment_notifier_client().await; let mut buf = Vec::with_capacity(unsubscribe_request.encoded_len()); unsubscribe_request diff --git a/libs/sdk-core/src/models.rs b/libs/sdk-core/src/models.rs index 5882628e5..348693d3b 100644 --- a/libs/sdk-core/src/models.rs +++ b/libs/sdk-core/src/models.rs @@ -8,6 +8,7 @@ use ripemd::Digest; use ripemd::Ripemd160; use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef}; use rusqlite::ToSql; +use sdk_common::grpc; use sdk_common::prelude::Network::*; use sdk_common::prelude::*; use serde::{Deserialize, Serialize}; @@ -19,14 +20,8 @@ use crate::bitcoin::hashes::hex::{FromHex, ToHex}; use crate::bitcoin::hashes::{sha256, Hash}; use crate::bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use crate::bitcoin::{Address, Script}; -use crate::breez_services::BreezServer; -use crate::ensure_sdk; use crate::error::SdkResult; use crate::fiat::{FiatCurrency, Rate}; -use crate::grpc::{ - self, GetReverseRoutingNodeRequest, PaymentInformation, RegisterPaymentNotificationResponse, - RegisterPaymentReply, RemovePaymentNotificationResponse, -}; use crate::lsp::LspInformation; use crate::persist::swap::SwapChainInfo; use crate::swap_in::error::{SwapError, SwapResult}; @@ -68,7 +63,7 @@ pub trait LspAPI: Send + Sync { lsp_pubkey: Vec, webhook_url: String, webhook_url_signature: String, - ) -> SdkResult; + ) -> SdkResult; /// Unregister for webhook callbacks for the given `webhook_url` async fn unregister_payment_notifications( @@ -77,15 +72,15 @@ pub trait LspAPI: Send + Sync { lsp_pubkey: Vec, webhook_url: String, webhook_url_signature: String, - ) -> SdkResult; + ) -> SdkResult; /// Register a payment to open a new channel with the LSP async fn register_payment( &self, lsp_id: String, lsp_pubkey: Vec, - payment_info: PaymentInformation, - ) -> SdkResult; + payment_info: grpc::PaymentInformation, + ) -> SdkResult; } /// Trait covering fiat-related functionality @@ -420,8 +415,8 @@ impl ReverseSwapperRoutingAPI for BreezServer { async fn fetch_reverse_routing_node(&self) -> ReverseSwapResult> { Ok(self .get_swapper_client() - .await? - .get_reverse_routing_node(GetReverseRoutingNodeRequest::default()) + .await + .get_reverse_routing_node(grpc::GetReverseRoutingNodeRequest::default()) .await .map(|reply| reply.into_inner().node_id)?) } @@ -1170,7 +1165,7 @@ impl OpeningFeeParamsMenu { /// This struct should not be persisted as such, because validation happens dynamically based on /// the current time. At a later point in time, any previously-validated [OpeningFeeParamsMenu] /// could be invalid. Therefore, the [OpeningFeeParamsMenu] should always be initialized on-the-fly. - pub fn try_from(values: Vec) -> Result { + pub fn try_from(values: Vec) -> Result { let temp = Self { values: values .into_iter() @@ -1609,8 +1604,8 @@ mod tests { use anyhow::Result; use prost::Message; use rand::random; + use sdk_common::grpc; - use crate::grpc::PaymentInformation; use crate::test_utils::{get_test_ofp, rand_vec_u8}; use crate::{OpeningFeeParams, PaymentPath, PaymentPathEdge}; @@ -1746,7 +1741,7 @@ mod tests { #[test] fn test_payment_information_ser_de() -> Result<()> { - let dummy_payment_info = PaymentInformation { + let dummy_payment_info = grpc::PaymentInformation { payment_hash: rand_vec_u8(10), payment_secret: rand_vec_u8(10), destination: rand_vec_u8(10), @@ -1759,7 +1754,7 @@ mod tests { let mut buf = Vec::with_capacity(dummy_payment_info.encoded_len()); dummy_payment_info.encode(&mut buf)?; - let decoded_payment_info: PaymentInformation = PaymentInformation::decode(&*buf)?; + let decoded_payment_info = grpc::PaymentInformation::decode(&*buf)?; assert_eq!(dummy_payment_info, decoded_payment_info); diff --git a/libs/sdk-core/src/moonpay.rs b/libs/sdk-core/src/moonpay.rs index 368035b86..e8213004e 100644 --- a/libs/sdk-core/src/moonpay.rs +++ b/libs/sdk-core/src/moonpay.rs @@ -1,8 +1,8 @@ use anyhow::Result; use reqwest::Url; +use sdk_common::grpc::SignUrlRequest; +use sdk_common::prelude::BreezServer; -use crate::breez_services::BreezServer; -use crate::grpc::SignUrlRequest; use crate::SwapInfo; #[derive(Clone)] @@ -59,7 +59,7 @@ impl MoonPayApi for BreezServer { format!("{:.8}", swap_info.max_allowed_deposit as f64 / 100000000.0).as_str(), ) .await?; - let mut signer = self.get_signer_client().await?.clone(); + let mut signer = self.get_signer_client().await; let signed_url = signer .sign_url(SignUrlRequest { base_url: config.base_url.clone(), diff --git a/libs/sdk-core/src/node_api.rs b/libs/sdk-core/src/node_api.rs index bfd664890..82ae18a0d 100644 --- a/libs/sdk-core/src/node_api.rs +++ b/libs/sdk-core/src/node_api.rs @@ -12,7 +12,7 @@ use crate::{ lightning_invoice::RawBolt11Invoice, persist::error::PersistError, CustomMessage, LspInformation, MaxChannelAmount, NodeCredentials, Payment, PaymentResponse, - PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, RouteHint, RouteHintHop, + PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, SyncResponse, TlvEntry, }; use crate::error::LnUrlAuthError; diff --git a/libs/sdk-core/src/persist/swap.rs b/libs/sdk-core/src/persist/swap.rs index e8034e448..db83b16ab 100644 --- a/libs/sdk-core/src/persist/swap.rs +++ b/libs/sdk-core/src/persist/swap.rs @@ -1,12 +1,12 @@ -use crate::models::{SwapInfo, SwapStatus}; +use rusqlite::{named_params, OptionalExtension, Params, Row, Transaction, TransactionBehavior}; + +use crate::models::{OpeningFeeParams, SwapInfo, SwapStatus}; use super::{ db::{SqliteStorage, StringArray}, error::PersistError, error::PersistResult, }; -use crate::OpeningFeeParams; -use rusqlite::{named_params, OptionalExtension, Params, Row, Transaction, TransactionBehavior}; #[derive(Debug, Clone)] pub(crate) struct SwapChainInfo { diff --git a/libs/sdk-core/src/support.rs b/libs/sdk-core/src/support.rs index 79775a8e0..08699fdd4 100644 --- a/libs/sdk-core/src/support.rs +++ b/libs/sdk-core/src/support.rs @@ -1,11 +1,12 @@ use std::time::SystemTime; -use crate::error::SdkResult; -use crate::grpc::{BreezStatusRequest, ReportPaymentFailureRequest}; -use crate::{breez_services::BreezServer, error::SdkError}; +use crate::error::{SdkError, SdkResult}; use crate::{HealthCheckStatus, NodeState, Payment, ServiceHealthCheckResponse, SupportAPI}; + use anyhow::anyhow; use chrono::{DateTime, Utc}; +use sdk_common::grpc::{BreezStatusRequest, ReportPaymentFailureRequest}; +use sdk_common::prelude::BreezServer; use serde::{Deserialize, Serialize}; use tonic::Request; diff --git a/libs/sdk-core/src/swap_in/swap.rs b/libs/sdk-core/src/swap_in/swap.rs index 6b0247bea..bf2342243 100644 --- a/libs/sdk-core/src/swap_in/swap.rs +++ b/libs/sdk-core/src/swap_in/swap.rs @@ -5,6 +5,8 @@ use std::time::{SystemTime, UNIX_EPOCH}; use anyhow::{anyhow, Result}; use rand::Rng; use ripemd::{Digest, Ripemd160}; +use sdk_common::grpc::{AddFundInitRequest, GetSwapPaymentRequest}; +use sdk_common::prelude::BreezServer; use tokio::sync::broadcast; use crate::bitcoin::blockdata::constants::WITNESS_SCALE_FACTOR; @@ -18,17 +20,16 @@ use crate::bitcoin::util::sighash::SighashCache; use crate::bitcoin::{ Address, EcdsaSighashType, Script, Sequence, Transaction, TxIn, TxOut, Witness, }; -use crate::breez_services::{BreezEvent, BreezServer, OpenChannelParams, Receiver}; +use crate::breez_services::{BreezEvent, OpenChannelParams, Receiver}; use crate::chain::{get_total_incoming_txs, get_utxos, AddressUtxos, ChainService}; use crate::error::ReceivePaymentError; -use crate::grpc::{AddFundInitRequest, GetSwapPaymentRequest}; use crate::models::{Swap, SwapInfo, SwapStatus, SwapperAPI}; use crate::node_api::NodeAPI; use crate::persist::error::PersistResult; use crate::persist::swap::SwapChainInfo; use crate::swap_in::error::SwapError; use crate::{ - OpeningFeeParams, PrepareRefundRequest, PrepareRefundResponse, ReceivePaymentRequest, + models::OpeningFeeParams, PrepareRefundRequest, PrepareRefundResponse, ReceivePaymentRequest, RefundRequest, RefundResponse, SWAP_PAYMENT_FEE_EXPIRY_SECONDS, }; @@ -42,7 +43,7 @@ impl SwapperAPI for BreezServer { payer_pubkey: Vec, node_id: String, ) -> SwapResult { - let mut fund_client = self.get_swapper_client().await?; + let mut fund_client = self.get_swapper_client().await; let req = AddFundInitRequest { hash: hash.clone(), pubkey: payer_pubkey.clone(), @@ -68,7 +69,7 @@ impl SwapperAPI for BreezServer { }; let resp = self .get_swapper_client() - .await? + .await .get_swap_payment(req) .await? .into_inner(); diff --git a/libs/sdk-core/src/swap_out/reverseswap.rs b/libs/sdk-core/src/swap_out/reverseswap.rs index 57faaca4b..154e01b68 100644 --- a/libs/sdk-core/src/swap_out/reverseswap.rs +++ b/libs/sdk-core/src/swap_out/reverseswap.rs @@ -24,8 +24,8 @@ use crate::swap_in::swap::create_swap_keys; use crate::{ ensure_sdk, BreezEvent, Config, FullReverseSwapInfo, PayOnchainRequest, PaymentStatus, ReverseSwapInfo, ReverseSwapInfoCached, ReverseSwapPairInfo, ReverseSwapStatus, + ReverseSwapStatus::*, RouteHintHop, SendOnchainRequest, }; -use crate::{ReverseSwapStatus::*, RouteHintHop, SendOnchainRequest}; // Estimates based on https://github.com/BoltzExchange/boltz-backend/blob/master/lib/rates/FeeProvider.ts#L31-L42 pub const ESTIMATED_CLAIM_TX_VSIZE: u64 = 138; diff --git a/libs/sdk-core/src/test_utils.rs b/libs/sdk-core/src/test_utils.rs index 67e5febaf..68d47eb90 100644 --- a/libs/sdk-core/src/test_utils.rs +++ b/libs/sdk-core/src/test_utils.rs @@ -12,6 +12,7 @@ use rand::distributions::uniform::{SampleRange, SampleUniform}; use rand::distributions::{Alphanumeric, DistString, Standard}; use rand::rngs::OsRng; use rand::{random, Rng}; +use sdk_common::grpc; use tokio::sync::{mpsc, watch, Mutex}; use tokio::time::sleep; use tokio_stream::Stream; @@ -29,10 +30,6 @@ use crate::breez_services::{OpenChannelParams, Receiver}; use crate::chain::{ChainService, OnchainTx, Outspend, RecommendedFees, TxStatus}; use crate::error::{ReceivePaymentError, SdkError, SdkResult}; use crate::fiat::{FiatCurrency, Rate}; -use crate::grpc::{ - PaymentInformation, RegisterPaymentNotificationResponse, RegisterPaymentReply, - RemovePaymentNotificationResponse, -}; use crate::invoice::{InvoiceError, InvoiceResult}; use crate::lightning::ln::PaymentSecret; use crate::lightning_invoice::{Currency, InvoiceBuilder, RawBolt11Invoice}; @@ -49,7 +46,7 @@ use crate::swap_out::boltzswap::{BoltzApiCreateReverseSwapResponse, BoltzApiReve use crate::swap_out::error::{ReverseSwapError, ReverseSwapResult}; use crate::{ parse_invoice, Config, CustomMessage, LNInvoice, MaxChannelAmount, NodeCredentials, - OpeningFeeParams, OpeningFeeParamsMenu, PaymentResponse, PrepareRedeemOnchainFundsRequest, + OpeningFeeParamsMenu, PaymentResponse, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse, ReceivePaymentRequest, ReverseSwapPairInfo, RouteHint, RouteHintHop, SwapInfo, }; @@ -667,8 +664,8 @@ impl LspAPI for MockBreezServer { _lsp_pubkey: Vec, _webhook_url: String, _webhook_url_signature: String, - ) -> SdkResult { - Ok(RegisterPaymentNotificationResponse {}) + ) -> SdkResult { + Ok(grpc::RegisterPaymentNotificationResponse {}) } async fn unregister_payment_notifications( @@ -677,17 +674,17 @@ impl LspAPI for MockBreezServer { _lsp_pubkey: Vec, _webhook_url: String, _webhook_url_signature: String, - ) -> SdkResult { - Ok(RemovePaymentNotificationResponse {}) + ) -> SdkResult { + Ok(grpc::RemovePaymentNotificationResponse {}) } async fn register_payment( &self, _lsp_id: String, _lsp_pubkey: Vec, - _payment_info: PaymentInformation, - ) -> SdkResult { - Ok(RegisterPaymentReply {}) + _payment_info: grpc::PaymentInformation, + ) -> SdkResult { + Ok(grpc::RegisterPaymentReply {}) } } @@ -839,7 +836,7 @@ fn sign_invoice(invoice: RawBolt11Invoice) -> String { } /// [OpeningFeeParams] that are valid for more than 48h -pub(crate) fn get_test_ofp_48h(min_msat: u64, proportional: u32) -> crate::grpc::OpeningFeeParams { +pub(crate) fn get_test_ofp_48h(min_msat: u64, proportional: u32) -> grpc::OpeningFeeParams { get_test_ofp_generic(min_msat, proportional, true, chrono::Duration::days(10)) } @@ -848,7 +845,7 @@ pub(crate) fn get_test_ofp( min_msat: u64, proportional: u32, future_or_past: bool, -) -> crate::grpc::OpeningFeeParams { +) -> grpc::OpeningFeeParams { get_test_ofp_generic( min_msat, proportional, @@ -862,7 +859,7 @@ pub(crate) fn get_test_ofp_generic( proportional: u32, future_or_past: bool, duration: chrono::Duration, -) -> crate::grpc::OpeningFeeParams { +) -> grpc::OpeningFeeParams { let now = Utc::now(); let date_time = match future_or_past { true => now.checked_add_signed(duration).unwrap(), @@ -870,7 +867,7 @@ pub(crate) fn get_test_ofp_generic( }; let formatted = date_time.to_rfc3339_opts(SecondsFormat::Millis, true); - OpeningFeeParams { + grpc::OpeningFeeParams { min_msat, proportional, valid_until: formatted, diff --git a/tools/sdk-cli/Cargo.lock b/tools/sdk-cli/Cargo.lock index 8f39c1163..e5a56140c 100644 --- a/tools/sdk-cli/Cargo.lock +++ b/tools/sdk-cli/Cargo.lock @@ -517,7 +517,6 @@ dependencies = [ "tokio", "tokio-stream", "tonic", - "tonic-build", "zbase32", ] @@ -2680,6 +2679,7 @@ dependencies = [ "lightning", "lightning-invoice", "log", + "prost", "querystring", "regex", "reqwest", @@ -2688,6 +2688,8 @@ dependencies = [ "serde_json", "strum_macros", "thiserror", + "tonic", + "tonic-build", ] [[package]]