diff --git a/src/error.rs b/src/error.rs index 6aae520..00d6ebe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,7 +10,8 @@ use cashu_sdk::lightning_invoice::ParseOrSemanticError; pub enum Error { DecodeInvoice, StatusCode(StatusCode), - _Ln(ln_rs::Error), + Ln(ln_rs::Error), + Custom(String), } impl std::error::Error for Error {} @@ -20,7 +21,8 @@ impl fmt::Display for Error { match self { Self::DecodeInvoice => write!(f, "Failed to decode LN Invoice"), Self::StatusCode(code) => write!(f, "{}", code), - Self::_Ln(code) => write!(f, "{}", code), + Self::Custom(err) => write!(f, "{}", err), + Self::Ln(code) => write!(f, "{}", code), } } } @@ -48,9 +50,12 @@ impl IntoResponse for Error { match self { Error::DecodeInvoice => (StatusCode::BAD_REQUEST, self.to_string()).into_response(), Error::StatusCode(code) => (code, "").into_response(), - Error::_Ln(code) => { + Error::Ln(code) => { (StatusCode::INTERNAL_SERVER_ERROR, code.to_string()).into_response() } + Error::Custom(msg) => { + (StatusCode::INTERNAL_SERVER_ERROR, msg.to_string()).into_response() + } } } } diff --git a/src/main.rs b/src/main.rs index 0ec2a5a..09c4baa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,11 +12,12 @@ use axum::http::header::{ ACCESS_CONTROL_ALLOW_CREDENTIALS, ACCESS_CONTROL_ALLOW_ORIGIN, AUTHORIZATION, CONTENT_TYPE, }; use axum::http::StatusCode; -use axum::response::Response; +use axum::response::{IntoResponse, Response}; use axum::routing::{get, post}; use axum::Router; use bip39::Mnemonic; use cashu_sdk::amount::Amount; +use cashu_sdk::error::ErrorResponse; use cashu_sdk::mint::{LocalStore, Mint, RedbLocalStore}; use cashu_sdk::nuts::nut02::Id; use cashu_sdk::nuts::{ @@ -25,12 +26,12 @@ use cashu_sdk::nuts::{ }; use cashu_sdk::types::MintQuote; use clap::Parser; -use error::into_response; +use error::{into_response, Error}; use futures::StreamExt; use ln_rs::{Bolt11Invoice, Ln}; use tokio::sync::Mutex; use tower_http::cors::CorsLayer; -use tracing::{debug, warn}; +use tracing::warn; use utils::unix_time; use crate::config::LnBackend; @@ -59,8 +60,6 @@ async fn main() -> anyhow::Result<()> { None => "./config.toml".to_string(), }; - debug!("Path: {}", config_file_arg); - let settings = config::Settings::new(&Some(config_file_arg)); let db_path = match args.db { @@ -68,7 +67,11 @@ async fn main() -> anyhow::Result<()> { None => settings.info.clone().db_path, }; - let localstore = RedbLocalStore::new(db_path.to_str().unwrap())?; + let db_path = db_path + .to_str() + .ok_or(Error::Custom("Invalid db_path".to_string()))?; + + let localstore = RedbLocalStore::new(db_path)?; let mint_info = MintInfo::default(); //settings.mint_info.clone(); localstore.set_mint_info(&mint_info).await?; @@ -84,23 +87,25 @@ async fn main() -> anyhow::Result<()> { ) .await?; - println!("Mint created"); - let last_pay_path = PathBuf::from_str(&settings.info.last_pay_path.clone())?; match fs::metadata(&last_pay_path) { Ok(_) => (), Err(_e) => { // Create the parent directory if it doesn't exist - fs::create_dir_all(last_pay_path.parent().unwrap())?; + fs::create_dir_all( + last_pay_path + .parent() + .ok_or(Error::Custom("Invalid last_pay_path".to_string()))?, + )?; // Attempt to create the file - let mut fs = File::create(&last_pay_path).unwrap(); - fs.write_all(&0_u64.to_be_bytes()).unwrap(); + let mut fs = File::create(&last_pay_path)?; + fs.write_all(&0_u64.to_be_bytes())?; } } - let last_pay = fs::read(&last_pay_path).unwrap(); + let last_pay = fs::read(&last_pay_path)?; let last_pay_index = u64::from_be_bytes(last_pay.try_into().unwrap_or([0, 0, 0, 0, 0, 0, 0, 0])); @@ -334,7 +339,17 @@ async fn get_mint_bolt11_quote( ) .await; - let invoice = invoice.unwrap(); + let invoice = if let Ok(invoice) = invoice { + invoice + } else { + warn!("Could not get ln invoice for mint quote"); + let response = ErrorResponse { + code: 99, + error: Some("Could not fetch ln invoice".to_string()), + detail: None, + }; + return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(response)).into_response()); + }; let quote = state .mint @@ -386,7 +401,11 @@ async fn get_melt_bolt11_quote( State(state): State, Json(payload): Json, ) -> Result, Response> { - let amount = payload.request.amount_milli_satoshis().unwrap() / 1000; + let amount = payload + .request + .amount_milli_satoshis() + .ok_or(Error::Custom("Invoice amount not defined".to_string()).into_response())? + / 1000; assert!(amount > 0); let quote = state .mint @@ -408,14 +427,14 @@ async fn get_melt_bolt11_quote( async fn get_check_melt_bolt11_quote( State(state): State, Path(quote_id): Path, -) -> Result, StatusCode> { +) -> Result, Response> { let quote = state .mint .lock() .await .check_melt_quote("e_id) .await - .unwrap(); + .map_err(into_response)?; Ok(Json(quote)) } @@ -423,34 +442,36 @@ async fn get_check_melt_bolt11_quote( async fn post_melt_bolt11( State(state): State, Json(payload): Json, -) -> Result, StatusCode> { +) -> Result, Response> { let quote = state .mint .lock() .await .verify_melt_request(&payload) .await - .map_err(|_| StatusCode::NOT_ACCEPTABLE)?; + .map_err(into_response)?; let pre = state .ln .ln_processor - .pay_invoice(Bolt11Invoice::from_str("e.request).unwrap(), None) + .pay_invoice( + Bolt11Invoice::from_str("e.request) + .map_err(|_| Error::DecodeInvoice.into_response())?, + None, + ) .await - .unwrap(); + .map_err(|err| Error::Ln(err).into_response())?; - let preimage = pre.payment_preimage; + let preimage = pre + .payment_preimage + .ok_or(Error::DecodeInvoice.into_response())?; let res = state .mint .lock() .await - .process_melt_request( - &payload, - &preimage.unwrap(), - Amount::from(pre.total_spent.to_sat()), - ) + .process_melt_request(&payload, &preimage, Amount::from(pre.total_spent.to_sat())) .await - .unwrap(); + .map_err(into_response)?; Ok(Json(res)) } @@ -493,6 +514,7 @@ async fn post_swap( .process_swap_request(payload) .await .map_err(into_response)?; + Ok(Json(swap_response)) }