Repository: MostroP2P/mostro
Pull request #459: Feature anyhow removal
Author: login: arkanoider
Created: 2025-03-02T10:58:05Z | Merged: 2025-03-03T19:59:03Z

@grunch

removed anyhow dependency.


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Chores**
  - Removed the `anyhow` dependency to streamline the project.
  
- **Refactor**
  - Unified error handling across core functionalities—such as payment processing, order management, and configuration setup—to deliver more precise and consistent error messages.
  - Updated various function signatures to utilize `MostroError` for enhanced error specificity.
  - Improved error handling in the Bitcoin price management functionality for better robustness.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/Cargo.lock b/Cargo.lock
index 84316dce..80b17497 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1949,7 +1949,6 @@ dependencies = [
 name = "mostro"
 version = "0.13.1"
 dependencies = [
- "anyhow",
  "bitcoin",
  "chrono",
  "clap",
@@ -1975,9 +1974,9 @@ dependencies = [
 
 [[package]]
 name = "mostro-core"
-version = "0.6.28"
+version = "0.6.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc439d283bc64ae1d8b6d7f83994ceec750f402d3e7515c97757ba684271eef4"
+checksum = "f50b052b77839590b542d90c88bed69c9eab9298c647dbccd3b27ccc19c7f1d5"
 dependencies = [
  "anyhow",
  "bitcoin",
diff --git a/Cargo.toml b/Cargo.toml
index 09b44b15..c581cb4c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,6 @@ name = "mostrod"
 path = "src/main.rs"
 
 [dependencies]
-anyhow = "1.0.89"
 chrono = "0.4.35"
 easy-hasher = "2.2.1"
 lightning-invoice = { version = "0.33.1", features = ["std"] }
@@ -38,7 +37,7 @@ uuid = { version = "1.8.0", features = [
   "serde",
 ] }
 reqwest = { version = "0.12.1", features = ["json"] }
-mostro-core = { version = "0.6.28", features = ["sqlx"] }
+mostro-core = { version = "0.6.30", features = ["sqlx"] }
 tracing = "0.1.40"
 tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
 config = "0.15.8"
diff --git a/src/app.rs b/src/app.rs
index a329280d..c1e3631a 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -40,7 +40,6 @@ use crate::util::enqueue_cant_do_msg;
 use crate::Settings;
 
 // External dependencies
-use anyhow::Result;
 use mostro_core::error::CantDoReason;
 use mostro_core::error::MostroError;
 use mostro_core::error::ServiceError;
@@ -354,7 +353,7 @@ pub async fn run(
                             {
                                 match e.downcast::<MostroError>() {
                                     Ok(err) => {
-                                        manage_errors(err, message, event, &action).await;
+                                        manage_errors(*err, message, event, &action).await;
                                     }
                                     Err(e) => {
                                         tracing::error!("Unexpected error type: {}", e);
diff --git a/src/app/add_invoice.rs b/src/app/add_invoice.rs
index cc1bae5b..4ef97639 100644
--- a/src/app/add_invoice.rs
+++ b/src/app/add_invoice.rs
@@ -2,8 +2,6 @@ use crate::util::{
     enqueue_order_msg, get_order, show_hold_invoice, update_order_event, validate_invoice,
 };
 
-use anyhow::Result;
-
 use mostro_core::error::MostroError::{self, *};
 use mostro_core::error::{CantDoReason, ServiceError};
 use mostro_core::message::{Action, Message, Payload};
diff --git a/src/app/admin_add_solver.rs b/src/app/admin_add_solver.rs
index 1a97db02..a5047c69 100644
--- a/src/app/admin_add_solver.rs
+++ b/src/app/admin_add_solver.rs
@@ -1,7 +1,6 @@
 use crate::db::add_new_user;
 use crate::util::send_dm;
 
-use anyhow::Result;
 use mostro_core::error::{
     MostroError::{self, *},
     ServiceError,
diff --git a/src/app/rate_user.rs b/src/app/rate_user.rs
index 679015bf..9743f5e5 100644
--- a/src/app/rate_user.rs
+++ b/src/app/rate_user.rs
@@ -1,7 +1,6 @@
 use crate::util::{enqueue_order_msg, get_order, update_user_rating_event};
 
 use crate::db::{is_user_present, update_user_rating};
-use anyhow::Result;
 use mostro_core::error::MostroError::{self, *};
 use mostro_core::error::{CantDoReason, ServiceError};
 use mostro_core::message::{Action, Message, Payload};
diff --git a/src/app/take_buy.rs b/src/app/take_buy.rs
index 6fbaa308..7f885730 100644
--- a/src/app/take_buy.rs
+++ b/src/app/take_buy.rs
@@ -3,7 +3,6 @@ use crate::util::{
 };
 
 use crate::db::{seller_has_pending_order, update_user_trade_index};
-use anyhow::Result;
 use mostro_core::error::MostroError::{self, *};
 use mostro_core::error::{CantDoReason, ServiceError};
 use mostro_core::message::Message;
diff --git a/src/app/take_sell.rs b/src/app/take_sell.rs
index 681881cd..adb1a644 100644
--- a/src/app/take_sell.rs
+++ b/src/app/take_sell.rs
@@ -7,7 +7,6 @@ use mostro_core::error::MostroError::{self, *};
 use mostro_core::error::{CantDoReason, ServiceError};
 
 use crate::db::{buyer_has_pending_order, update_user_trade_index};
-use anyhow::Result;
 use mostro_core::message::Message;
 use mostro_core::order::{Order, Status};
 use nostr::nips::nip59::UnwrappedGift;
diff --git a/src/bitcoin_price.rs b/src/bitcoin_price.rs
index af9b222b..a4686746 100644
--- a/src/bitcoin_price.rs
+++ b/src/bitcoin_price.rs
@@ -1,4 +1,5 @@
-use anyhow::Result;
+use mostro_core::error::MostroError::{self, *};
+use mostro_core::error::ServiceError;
 use once_cell::sync::Lazy;
 use serde::Deserialize;
 use std::collections::HashMap;
@@ -19,21 +20,33 @@ static BITCOIN_PRICES: Lazy<RwLock<HashMap<String, f64>>> =
 pub struct BitcoinPriceManager;
 
 impl BitcoinPriceManager {
-    pub async fn update_prices() -> Result<()> {
-        let response = reqwest::get(YADIO_API_URL).await?;
-        let yadio_response: YadioResponse = response.json().await?;
+    pub async fn update_prices() -> Result<(), MostroError> {
+        let response = reqwest::get(YADIO_API_URL)
+            .await
+            .map_err(|_| MostroInternalErr(ServiceError::NoAPIResponse))?;
+        let yadio_response: YadioResponse = response
+            .json()
+            .await
+            .map_err(|_| MostroInternalErr(ServiceError::MessageSerializationError))?;
         info!(
             "Bitcoin prices updated. Got BTC price in {} fiat currencies",
             yadio_response.btc.keys().collect::<Vec<&String>>().len()
         );
 
-        let mut prices_write = BITCOIN_PRICES.write().unwrap();
+        let mut prices_write = BITCOIN_PRICES
+            .write()
+            .map_err(|e| MostroInternalErr(ServiceError::IOError(e.to_string())))?;
         *prices_write = yadio_response.btc;
         Ok(())
     }
 
-    pub fn get_price(currency: &str) -> Option<f64> {
-        let prices_read = BITCOIN_PRICES.read().unwrap();
-        prices_read.get(currency).cloned()
+    pub fn get_price(currency: &str) -> Result<f64, MostroError> {
+        let prices_read: std::sync::RwLockReadGuard<'_, HashMap<String, f64>> = BITCOIN_PRICES
+            .read()
+            .map_err(|e| MostroInternalErr(ServiceError::IOError(e.to_string())))?;
+        prices_read
+            .get(currency)
+            .cloned()
+            .ok_or(MostroInternalErr(ServiceError::NoAPIResponse))
     }
 }
diff --git a/src/cli.rs b/src/cli.rs
index 1a4aefc3..92092a98 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -1,9 +1,8 @@
 pub mod settings;
 
 use crate::cli::settings::init_default_dir;
-
-use anyhow::Result;
 use clap::Parser;
+use mostro_core::error::MostroError;
 use std::path::PathBuf;
 
 #[derive(Parser)]
@@ -30,12 +29,12 @@ pub struct Cli {
     dirsettings: Option<String>,
 }
 
-pub fn settings_init() -> Result<PathBuf> {
+pub fn settings_init() -> Result<PathBuf, MostroError> {
     let cli = Cli::parse();
 
     if let Some(path) = cli.dirsettings.as_deref() {
-        init_default_dir(Some(path.to_string()))
+        Ok(init_default_dir(Some(path.to_string()))?)
     } else {
-        init_default_dir(None)
+        Ok(init_default_dir(None)?)
     }
 }
diff --git a/src/cli/settings.rs b/src/cli/settings.rs
index 1c4dc8ce..83447df8 100644
--- a/src/cli/settings.rs
+++ b/src/cli/settings.rs
@@ -1,6 +1,7 @@
 use crate::MOSTRO_CONFIG;
-use anyhow::{Error, Result};
 use config::{Config, ConfigError, Environment, File};
+use mostro_core::error::MostroError::{self, *};
+use mostro_core::error::ServiceError;
 use serde::Deserialize;
 use std::ffi::OsString;
 use std::io::Write;
@@ -46,9 +47,9 @@ pub struct Database {
 }
 
 impl TryFrom<Settings> for Database {
-    type Error = Error;
+    type Error = MostroError;
 
-    fn try_from(_: Settings) -> Result<Self, Error> {
+    fn try_from(_: Settings) -> Result<Self, MostroError> {
         Ok(MOSTRO_CONFIG.get().unwrap().database.clone())
     }
 }
@@ -66,9 +67,9 @@ pub struct Lightning {
 }
 
 impl TryFrom<Settings> for Lightning {
-    type Error = Error;
+    type Error = MostroError;
 
-    fn try_from(_: Settings) -> Result<Self, Error> {
+    fn try_from(_: Settings) -> Result<Self, MostroError> {
         Ok(MOSTRO_CONFIG.get().unwrap().lightning.clone())
     }
 }
@@ -80,9 +81,9 @@ pub struct Nostr {
 }
 
 impl TryFrom<Settings> for Nostr {
-    type Error = Error;
+    type Error = MostroError;
 
-    fn try_from(_: Settings) -> Result<Self, Error> {
+    fn try_from(_: Settings) -> Result<Self, MostroError> {
         Ok(MOSTRO_CONFIG.get().unwrap().nostr.clone())
     }
 }
@@ -103,9 +104,9 @@ pub struct Mostro {
 }
 
 impl TryFrom<Settings> for Mostro {
-    type Error = Error;
+    type Error = MostroError;
 
-    fn try_from(_: Settings) -> Result<Self, Error> {
+    fn try_from(_: Settings) -> Result<Self, MostroError> {
         Ok(MOSTRO_CONFIG.get().unwrap().mostro.clone())
     }
 }
@@ -169,7 +170,7 @@ impl Settings {
     }
 }
 
-pub fn init_default_dir(config_path: Option<String>) -> Result<PathBuf> {
+pub fn init_default_dir(config_path: Option<String>) -> Result<PathBuf, MostroError> {
     // , final_path : &mut PathBuf) -> Result<()> {
     // Dir prefix
     let home_dir: OsString;
@@ -183,7 +184,8 @@ pub fn init_default_dir(config_path: Option<String>) -> Result<PathBuf> {
         settings_dir_default.push(home_dir);
     } else {
         // Get $HOME from env
-        let tmp = std::env::var("HOME")?;
+        let tmp = std::env::var("HOME")
+            .map_err(|e| MostroInternalErr(ServiceError::EnvVarError(e.to_string())))?;
         // Os String
         home_dir = tmp.into();
         // Create default path with default .mostro value
@@ -199,10 +201,15 @@ pub fn init_default_dir(config_path: Option<String>) -> Result<PathBuf> {
         if std::fs::create_dir(settings_dir_default.clone()).is_ok() {
             tracing::info!("Created mostro default directory!");
             let mut config_file =
-                std::fs::File::create_new(settings_dir_default.join("settings.toml"))?;
+                std::fs::File::create_new(settings_dir_default.join("settings.toml"))
+                    .map_err(|e| MostroInternalErr(ServiceError::IOError(e.to_string())))?;
             let buf = include_bytes!("../../settings.tpl.toml");
-            config_file.write_all(buf)?;
-            config_file.flush()?;
+            config_file
+                .write_all(buf)
+                .map_err(|e| MostroInternalErr(ServiceError::IOError(e.to_string())))?;
+            config_file
+                .flush()
+                .map_err(|e| MostroInternalErr(ServiceError::IOError(e.to_string())))?;
         }
         tracing::info!(
             "Created settings file based on template and copied to {} directory",
diff --git a/src/db.rs b/src/db.rs
index e8b58d75..403fe3d2 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -1,4 +1,3 @@
-use anyhow::Result;
 use mostro_core::dispute::Dispute;
 use mostro_core::error::ServiceError;
 use mostro_core::error::{
@@ -20,7 +19,7 @@ use uuid::Uuid;
 
 use crate::cli::settings::Settings;
 
-pub async fn connect() -> Result<Pool<Sqlite>> {
+pub async fn connect() -> Result<Pool<Sqlite>, MostroError> {
     // Get mostro settings
     let db_settings = Settings::get_db();
     let mut db_url = db_settings.url;
@@ -29,13 +28,8 @@ pub async fn connect() -> Result<Pool<Sqlite>> {
     let tmp = db_url.replace("sqlite://", "");
     let db_path = Path::new(&tmp);
     let conn = if !db_path.exists() {
-        let _file = std::fs::File::create_new(db_path).map_err(|e| {
-            anyhow::anyhow!(
-                "Failed to create database file at {}: {}",
-                db_path.display(),
-                e
-            )
-        })?;
+        let _file = std::fs::File::create_new(db_path)
+            .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
         match SqlitePool::connect(&db_url).await {
             Ok(pool) => {
                 match sqlx::migrate!().run(&pool).await {
@@ -54,11 +48,9 @@ pub async fn connect() -> Result<Pool<Sqlite>> {
                                 "Failed to create database connection"
                             );
                         }
-                        return Err(anyhow::anyhow!(
-                            "Failed to create database connection at {}: {}",
-                            db_path.display(),
-                            e
-                        ));
+                        return Err(MostroInternalErr(ServiceError::DbAccessError(
+                            e.to_string(),
+                        )));
                     }
                 }
                 pool
@@ -69,21 +61,15 @@ pub async fn connect() -> Result<Pool<Sqlite>> {
                     path = %db_path.display(),
                     "Failed to create database connection"
                 );
-                return Err(anyhow::anyhow!(
-                    "Failed to create database connection at {}: {}",
-                    db_path.display(),
-                    e
-                ));
+                return Err(MostroInternalErr(ServiceError::DbAccessError(
+                    e.to_string(),
+                )));
             }
         }
     } else {
-        SqlitePool::connect(&db_url).await.map_err(|e| {
-            anyhow::anyhow!(
-                "Failed to connect to existing database at {}: {}",
-                db_path.display(),
-                e
-            )
-        })?
+        SqlitePool::connect(&db_url)
+            .await
+            .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?
     };
     Ok(conn)
 }
@@ -92,9 +78,12 @@ pub async fn edit_buyer_pubkey_order(
     pool: &SqlitePool,
     order_id: Uuid,
     buyer_pubkey: Option<String>,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
-    let rows_affected = sqlx::query!(
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -105,8 +94,9 @@ pub async fn edit_buyer_pubkey_order(
         order_id
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -115,9 +105,12 @@ pub async fn edit_seller_pubkey_order(
     pool: &SqlitePool,
     order_id: Uuid,
     seller_pubkey: Option<String>,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
-    let rows_affected = sqlx::query!(
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -128,13 +121,14 @@ pub async fn edit_seller_pubkey_order(
         order_id
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
 
-pub async fn find_order_by_hash(pool: &SqlitePool, hash: &str) -> anyhow::Result<Order> {
+pub async fn find_order_by_hash(pool: &SqlitePool, hash: &str) -> Result<Order, MostroError> {
     let order = sqlx::query_as::<_, Order>(
         r#"
           SELECT *
@@ -144,12 +138,13 @@ pub async fn find_order_by_hash(pool: &SqlitePool, hash: &str) -> anyhow::Result
     )
     .bind(hash)
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
 
-pub async fn find_order_by_date(pool: &SqlitePool) -> anyhow::Result<Vec<Order>> {
+pub async fn find_order_by_date(pool: &SqlitePool) -> Result<Vec<Order>, MostroError> {
     let expire_time = Timestamp::now();
     let order = sqlx::query_as::<_, Order>(
         r#"
@@ -160,12 +155,13 @@ pub async fn find_order_by_date(pool: &SqlitePool) -> anyhow::Result<Vec<Order>>
     )
     .bind(expire_time.to_string())
     .fetch_all(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
 
-pub async fn find_order_by_seconds(pool: &SqlitePool) -> anyhow::Result<Vec<Order>> {
+pub async fn find_order_by_seconds(pool: &SqlitePool) -> Result<Vec<Order>, MostroError> {
     let mostro_settings = Settings::get_mostro();
     let exp_seconds = mostro_settings.expiration_seconds as u64;
     let expire_time = Timestamp::now() - exp_seconds;
@@ -178,7 +174,8 @@ pub async fn find_order_by_seconds(pool: &SqlitePool) -> anyhow::Result<Vec<Orde
     )
     .bind(expire_time.to_string())
     .fetch_all(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
@@ -186,7 +183,7 @@ pub async fn find_order_by_seconds(pool: &SqlitePool) -> anyhow::Result<Vec<Orde
 pub async fn find_dispute_by_order_id(
     pool: &SqlitePool,
     order_id: Uuid,
-) -> anyhow::Result<Dispute> {
+) -> Result<Dispute, MostroError> {
     let dispute = sqlx::query_as::<_, Dispute>(
         r#"
           SELECT *
@@ -196,7 +193,8 @@ pub async fn find_dispute_by_order_id(
     )
     .bind(order_id)
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(dispute)
 }
@@ -206,12 +204,15 @@ pub async fn update_order_to_initial_state(
     order_id: Uuid,
     amount: i64,
     fee: i64,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
     let status = Status::Pending.to_string();
     let hash: Option<String> = None;
     let preimage: Option<String> = None;
-    let rows_affected = sqlx::query!(
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -234,8 +235,9 @@ pub async fn update_order_to_initial_state(
         order_id,
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -244,9 +246,12 @@ pub async fn edit_master_buyer_pubkey_order(
     pool: &SqlitePool,
     order_id: Uuid,
     master_buyer_pubkey: Option<String>,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
-    let rows_affected = sqlx::query!(
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -257,8 +262,9 @@ pub async fn edit_master_buyer_pubkey_order(
         order_id
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -267,9 +273,12 @@ pub async fn edit_master_seller_pubkey_order(
     pool: &SqlitePool,
     order_id: Uuid,
     master_seller_pubkey: Option<String>,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
-    let rows_affected = sqlx::query!(
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -280,17 +289,24 @@ pub async fn edit_master_seller_pubkey_order(
         order_id
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
 
-pub async fn reset_order_taken_at_time(pool: &SqlitePool, order_id: Uuid) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
+pub async fn reset_order_taken_at_time(
+    pool: &SqlitePool,
+    order_id: Uuid,
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
     let taken_at = 0;
 
-    let rows_affected = sqlx::query!(
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -301,8 +317,9 @@ pub async fn reset_order_taken_at_time(pool: &SqlitePool, order_id: Uuid) -> any
         order_id,
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -311,9 +328,12 @@ pub async fn update_order_invoice_held_at_time(
     pool: &SqlitePool,
     order_id: Uuid,
     invoice_held_at: i64,
-) -> anyhow::Result<bool> {
-    let mut conn = pool.acquire().await?;
-    let rows_affected = sqlx::query!(
+) -> Result<bool, MostroError> {
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let result = sqlx::query!(
         r#"
             UPDATE orders
             SET
@@ -324,13 +344,14 @@ pub async fn update_order_invoice_held_at_time(
         order_id,
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
 
-pub async fn find_held_invoices(pool: &SqlitePool) -> anyhow::Result<Vec<Order>> {
+pub async fn find_held_invoices(pool: &SqlitePool) -> Result<Vec<Order>, MostroError> {
     let order = sqlx::query_as::<_, Order>(
         r#"
           SELECT *
@@ -339,12 +360,13 @@ pub async fn find_held_invoices(pool: &SqlitePool) -> anyhow::Result<Vec<Order>>
         "#,
     )
     .fetch_all(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
 
-pub async fn find_failed_payment(pool: &SqlitePool) -> anyhow::Result<Vec<Order>> {
+pub async fn find_failed_payment(pool: &SqlitePool) -> Result<Vec<Order>, MostroError> {
     let order = sqlx::query_as::<_, Order>(
         r#"
           SELECT *
@@ -353,12 +375,16 @@ pub async fn find_failed_payment(pool: &SqlitePool) -> anyhow::Result<Vec<Order>
         "#,
     )
     .fetch_all(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
 
-pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyhow::Result<User> {
+pub async fn find_solver_pubkey(
+    pool: &SqlitePool,
+    solver_npub: String,
+) -> Result<User, MostroError> {
     let user = sqlx::query_as::<_, User>(
         r#"
           SELECT *
@@ -369,12 +395,13 @@ pub async fn find_solver_pubkey(pool: &SqlitePool, solver_npub: String) -> anyho
     )
     .bind(solver_npub)
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(user)
 }
 
-pub async fn is_user_present(pool: &SqlitePool, public_key: String) -> anyhow::Result<User> {
+pub async fn is_user_present(pool: &SqlitePool, public_key: String) -> Result<User, MostroError> {
     let user = sqlx::query_as::<_, User>(
         r#"
             SELECT *
@@ -385,15 +412,16 @@ pub async fn is_user_present(pool: &SqlitePool, public_key: String) -> anyhow::R
     )
     .bind(public_key)
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(user)
 }
 
-pub async fn add_new_user(pool: &SqlitePool, new_user: User) -> anyhow::Result<()> {
+pub async fn add_new_user(pool: &SqlitePool, new_user: User) -> Result<(), MostroError> {
     // Validate public key format (32-bytes hex)
     let created_at: Timestamp = Timestamp::now();
-    let result = sqlx::query(
+    let _result = sqlx::query(
         "
             INSERT INTO users (pubkey, is_admin, is_solver, is_banned, category, last_trade_index, total_reviews, total_rating, last_rating, max_rating, min_rating, created_at) 
             VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)
@@ -412,34 +440,32 @@ pub async fn add_new_user(pool: &SqlitePool, new_user: User) -> anyhow::Result<(
     .bind(new_user.min_rating)
     .bind(created_at.to_string())
     .execute(pool)
-    .await;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
-    match result {
-        Ok(_) => {
-            tracing::info!("New user created successfully");
-            Ok(())
-        }
-        Err(e) => Err(anyhow::anyhow!("Error creating new user: {}", e)),
-    }
+    Ok(())
 }
 
 pub async fn update_user_trade_index(
     pool: &SqlitePool,
     public_key: String,
     trade_index: i64,
-) -> anyhow::Result<bool> {
+) -> Result<bool, MostroError> {
     // Validate public key format (32-bytes hex)
     if !public_key.chars().all(|c| c.is_ascii_hexdigit()) || public_key.len() != 64 {
-        return Err(anyhow::anyhow!("Invalid public key format"));
+        return Err(MostroCantDo(CantDoReason::InvalidPubkey));
     }
     // Validate trade_index
     if trade_index < 0 {
-        return Err(anyhow::anyhow!("Invalid trade_index: must be non-negative"));
+        return Err(MostroCantDo(CantDoReason::InvalidTradeIndex));
     }
 
-    let mut conn = pool.acquire().await?;
+    let mut conn = pool
+        .acquire()
+        .await
+        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
-    let rows_affected = sqlx::query!(
+    let result = sqlx::query!(
         r#"
             UPDATE users SET last_trade_index = ?1 WHERE pubkey = ?2
         "#,
@@ -447,8 +473,9 @@ pub async fn update_user_trade_index(
         public_key,
     )
     .execute(&mut conn)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -457,7 +484,7 @@ pub async fn update_user_trade_index(
 pub async fn seller_has_pending_order(
     pool: &SqlitePool,
     pubkey: String,
-) -> anyhow::Result<bool, MostroError> {
+) -> Result<bool, MostroError> {
     // Validate public key format (32-bytes hex)
     if !pubkey.chars().all(|c| c.is_ascii_hexdigit()) || pubkey.len() != 64 {
         return Err(MostroCantDo(CantDoReason::InvalidPubkey));
@@ -484,7 +511,7 @@ pub async fn seller_has_pending_order(
 pub async fn buyer_has_pending_order(
     pool: &SqlitePool,
     pubkey: String,
-) -> anyhow::Result<bool, MostroError> {
+) -> Result<bool, MostroError> {
     // Validate public key format (32-bytes hex)
     if !pubkey.chars().all(|c| c.is_ascii_hexdigit()) || pubkey.len() != 64 {
         return Err(MostroCantDo(CantDoReason::InvalidPubkey));
@@ -515,30 +542,28 @@ pub async fn update_user_rating(
     max_rating: i64,
     total_reviews: i64,
     total_rating: f64,
-) -> anyhow::Result<bool> {
+) -> Result<bool, MostroError> {
     // Validate public key format (32-bytes hex)
     if !public_key.chars().all(|c| c.is_ascii_hexdigit()) || public_key.len() != 64 {
-        return Err(anyhow::anyhow!("Invalid public key format"));
+        return Err(MostroCantDo(CantDoReason::InvalidPubkey));
     }
     // Validate rating values
     if !(0..=5).contains(&last_rating) {
-        return Err(anyhow::anyhow!("Invalid rating value"));
+        return Err(MostroCantDo(CantDoReason::InvalidRating));
     }
     if !(0..=5).contains(&min_rating) || !(0..=5).contains(&max_rating) {
-        return Err(anyhow::anyhow!("Invalid min/max rating values"));
+        return Err(MostroCantDo(CantDoReason::InvalidRating));
     }
     if MIN_RATING as i64 > last_rating || last_rating > MAX_RATING as i64 {
-        return Err(anyhow::anyhow!(
-            "Rating values must satisfy: min_rating <= last_rating <= max_rating"
-        ));
+        return Err(MostroCantDo(CantDoReason::InvalidRating));
     }
     if total_reviews < 0 {
-        return Err(anyhow::anyhow!("Invalid total reviews"));
+        return Err(MostroCantDo(CantDoReason::InvalidRating));
     }
     if total_rating < 0.0 || total_rating > (total_reviews * 5) as f64 {
-        return Err(anyhow::anyhow!("Invalid total rating"));
+        return Err(MostroCantDo(CantDoReason::InvalidRating));
     }
-    let rows_affected = sqlx::query!(
+    let result = sqlx::query!(
         r#"
             UPDATE users SET last_rating = ?1, min_rating = ?2, max_rating = ?3, total_reviews = ?4, total_rating = ?5 WHERE pubkey = ?6
         "#,
@@ -550,8 +575,9 @@ pub async fn update_user_rating(
         public_key,
     )
     .execute(pool)
-    .await?
-    .rows_affected();
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let rows_affected = result.rows_affected();
 
     Ok(rows_affected > 0)
 }
@@ -560,7 +586,7 @@ pub async fn is_assigned_solver(
     pool: &SqlitePool,
     solver_pubkey: &str,
     order_id: Uuid,
-) -> anyhow::Result<bool> {
+) -> Result<bool, MostroError> {
     println!("solver_pubkey: {}", solver_pubkey);
     println!("order_id: {}", order_id);
     let result = sqlx::query(
@@ -570,7 +596,8 @@ pub async fn is_assigned_solver(
     .bind(order_id)
     .map(|row: SqliteRow| row.get(0))
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(result)
 }
@@ -579,7 +606,7 @@ pub async fn find_order_by_id(
     pool: &SqlitePool,
     order_id: Uuid,
     user_pubkey: &str,
-) -> anyhow::Result<Order> {
+) -> Result<Order, MostroError> {
     let order = sqlx::query_as::<_, Order>(
         r#"
           SELECT *
@@ -590,7 +617,8 @@ pub async fn find_order_by_id(
     .bind(order_id)
     .bind(user_pubkey)
     .fetch_one(pool)
-    .await?;
+    .await
+    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
 
     Ok(order)
 }
diff --git a/src/lightning/mod.rs b/src/lightning/mod.rs
index 944c5fa3..8a0836bd 100644
--- a/src/lightning/mod.rs
+++ b/src/lightning/mod.rs
@@ -4,7 +4,6 @@ use crate::cli::settings::Settings;
 use crate::lightning::invoice::decode_invoice;
 use crate::util::bytes_to_string;
 
-use anyhow::Result;
 use easy_hasher::easy_hasher::*;
 use fedimint_tonic_lnd::invoicesrpc::{
     AddHoldInvoiceRequest, AddHoldInvoiceResp, CancelInvoiceMsg, CancelInvoiceResp,
diff --git a/src/main.rs b/src/main.rs
index 50f8d889..2893421d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,9 +15,8 @@ use crate::app::run;
 use crate::cli::settings::{init_global_settings, Settings};
 use crate::cli::settings_init;
 use crate::lightning::LnStatus;
-use anyhow::Result;
-use db::find_held_invoices;
-use lightning::LndConnector;
+use crate::db::find_held_invoices;
+use crate::lightning::LndConnector;
 use mostro_core::message::Message;
 use nostr_sdk::prelude::*;
 use scheduler::start_scheduler;
diff --git a/src/messages.rs b/src/messages.rs
index ad394abe..61914afe 100644
--- a/src/messages.rs
+++ b/src/messages.rs
@@ -1,10 +1,10 @@
-use anyhow::Result;
+use mostro_core::error::MostroError;
 
 pub fn hold_invoice_description(
     order_id: &str,
     fiat_code: &str,
     fiat_amount: &str,
-) -> Result<String> {
+) -> Result<String, MostroError> {
     Ok(format!(
         "Escrow amount Order #{order_id}: SELL BTC for {fiat_code} {fiat_amount} - It WILL FREEZE IN WALLET. It will release once you release. It will return if buyer does not confirm the payment"
     ))
diff --git a/src/scheduler.rs b/src/scheduler.rs
index 0685bf71..10d62d4c 100644
--- a/src/scheduler.rs
+++ b/src/scheduler.rs
@@ -9,6 +9,8 @@ use crate::{db::*, MESSAGE_QUEUES};
 use crate::{Keys, PublicKey};
 
 use chrono::{TimeDelta, Utc};
+use mostro_core::error::MostroError::{self, *};
+use mostro_core::error::ServiceError;
 use mostro_core::message::Message;
 use mostro_core::order::{Kind, Status};
 use nostr_sdk::EventBuilder;
@@ -230,16 +232,24 @@ async fn job_update_rate_events() {
     });
 }
 
-async fn job_cancel_orders() -> anyhow::Result<()> {
+async fn job_cancel_orders() -> Result<(), MostroError> {
     info!("Create a pool to connect to db");
 
     let pool = match connect().await {
         Ok(p) => p,
-        Err(e) => return Err(anyhow::Error::msg(e.to_string())),
+        Err(e) => {
+            return Err(MostroInternalErr(ServiceError::DbAccessError(
+                e.to_string(),
+            )))
+        }
     };
     let keys = match get_keys() {
         Ok(keys) => keys,
-        Err(e) => return Err(anyhow::Error::msg(e.to_string())),
+        Err(e) => {
+            return Err(MostroInternalErr(ServiceError::DbAccessError(
+                e.to_string(),
+            )))
+        }
     };
 
     let mut ln_client = LndConnector::new().await?;
diff --git a/src/util.rs b/src/util.rs
index 79b5c862..a0870dfb 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -64,7 +64,6 @@ pub async fn retries_yadio_request(
 
 pub fn get_bitcoin_price(fiat_code: &str) -> Result<f64, MostroError> {
     BitcoinPriceManager::get_price(fiat_code)
-        .ok_or(MostroError::MostroInternalErr(ServiceError::NoAPIResponse))
 }
 
 /// Request market quote from Yadio to have sats amount at actual market price
@@ -540,7 +539,7 @@ pub async fn show_hold_invoice(
 }
 
 // Create function to reuse in case of resubscription
-pub async fn invoice_subscribe(hash: Vec<u8>, request_id: Option<u64>) -> anyhow::Result<()> {
+pub async fn invoice_subscribe(hash: Vec<u8>, request_id: Option<u64>) -> Result<(), MostroError> {
     let mut ln_client_invoices = lightning::LndConnector::new().await?;
     let (tx, mut rx) = channel(100);
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>src/bitcoin_price.rs (1)</summary><blockquote>

`43-51`: **Enhanced return type for get_price method.**

The method has been improved to return `Result<f64, MostroError>` instead of `Option<f64>`, which provides better error information when price retrieval fails. The error handling is properly implemented using map_err and ok_or.


Consider adding a more specific error message when a currency is not found, such as including the currency code in the error:

```diff
- .ok_or(MostroInternalErr(ServiceError::NoAPIResponse))
+ .ok_or(MostroInternalErr(ServiceError::NoAPIResponse(format!("Price for currency '{}' not found", currency))))
```

This would require updating the ServiceError enum to accept a String for the NoAPIResponse variant.

</blockquote></details>
<details>
<summary>src/db.rs (2)</summary><blockquote>

`590-591`: **Remove debug print statements.**

These println statements appear to be leftover debugging code that should be removed or replaced with proper logging.

```diff
-    println!("solver_pubkey: {}", solver_pubkey);
-    println!("order_id: {}", order_id);
+    // Use tracing module for logging if needed
+    tracing::debug!("Checking if solver {} is assigned to order {}", solver_pubkey, order_id);
```

---

`22-624`: **Consider extracting the common error mapping pattern into a helper function.**

Throughout the file, there's a repetitive pattern of mapping SQLx errors to `MostroInternalErr`. Creating a helper function would reduce duplication and make the code more maintainable.

You could create a helper function like this:

```rust
fn map_db_err<T>(result: Result<T, sqlx::Error>) -> Result<T, MostroError> {
    result.map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))
}
```

Then use it in your code:

```diff
-    let mut conn = pool
-        .acquire()
-        .await
-        .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    let mut conn = map_db_err(pool.acquire().await)?;
```

And for query execution:

```diff
-    .await
-    .map_err(|e| MostroInternalErr(ServiceError::DbAccessError(e.to_string())))?;
+    .await
+    .pipe(map_db_err)?;
```

The `.pipe()` method would require the `tap` crate or similar function composition utility, but this approach would significantly reduce code duplication.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 4176c72eb65b65255ce7de0b84bc8062938ccb30 and 8c21b901eac730c5ff033e2ecc469f580712f6d3.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `Cargo.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (16)</summary>

* `Cargo.toml` (1 hunks)
* `src/app.rs` (1 hunks)
* `src/app/add_invoice.rs` (0 hunks)
* `src/app/admin_add_solver.rs` (0 hunks)
* `src/app/rate_user.rs` (0 hunks)
* `src/app/take_buy.rs` (0 hunks)
* `src/app/take_sell.rs` (0 hunks)
* `src/bitcoin_price.rs` (2 hunks)
* `src/cli.rs` (2 hunks)
* `src/cli/settings.rs` (8 hunks)
* `src/db.rs` (34 hunks)
* `src/lightning/mod.rs` (0 hunks)
* `src/main.rs` (1 hunks)
* `src/messages.rs` (1 hunks)
* `src/scheduler.rs` (2 hunks)
* `src/util.rs` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (6)</summary>

* src/app/take_sell.rs
* src/app/take_buy.rs
* src/app/add_invoice.rs
* src/app/rate_user.rs
* src/lightning/mod.rs
* src/app/admin_add_solver.rs

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* src/main.rs

</details>

<details>
<summary>🔇 Additional comments (21)</summary><blockquote>

<details>
<summary>Cargo.toml (1)</summary>

`53-54`: **LGTM! The patch configuration is a good approach for local development.**

The PR successfully removes the `anyhow` dependency and adds a local path reference to `mostro-core` in the patch section. This setup is beneficial for development as it allows you to work with a local version of the core library while implementing the error handling changes.

</details>
<details>
<summary>src/app.rs (1)</summary>

`356-356`: **Fixed error handling to dereference the `MostroError` correctly.**

The code properly dereferences the error with `*err` when passing it to the `manage_errors` function. This change is necessary after switching from `anyhow::Result` to the custom `MostroError` type.

</details>
<details>
<summary>src/cli.rs (3)</summary>

`5-5`: **LGTM! Appropriate import for the new error handling approach.**

This import properly replaces the previous `anyhow::Result` dependency with the project-specific error type.

---

`32-32`: **Function signature updated to use the custom error type.**

The return type now explicitly specifies `MostroError` as the error type, which enhances clarity and type safety.

---

`36-36`: **Function return values properly wrapped with `Ok`.**

The return values are now properly wrapped with `Ok()` to match the new function signature. This ensures type consistency throughout the error handling chain.



Also applies to: 38-38

</details>
<details>
<summary>src/messages.rs (2)</summary>

`1-1`: **LGTM! Appropriate import for the new error handling approach.**

This import properly replaces the previous `anyhow::Result` dependency with the project-specific error type.

---

`7-7`: **Function signature updated to use the custom error type.**

The return type now explicitly specifies `MostroError` as the error type, which enhances clarity and type safety.

</details>
<details>
<summary>src/scheduler.rs (4)</summary>

`12-13`: **Appropriate import of custom error types.**

Good addition of imports for the custom MostroError and ServiceError types that are part of the PR's main goal to replace anyhow.

---

`235-235`: **Updated function signature correctly.**

The function signature has been properly updated to return `Result<(), MostroError>` instead of `anyhow::Result<()>`, which aligns with the PR objective of removing anyhow dependency.

---

`240-244`: **Improved error handling with specific error types.**

Error handling has been properly refactored to use the custom error type hierarchy. This provides more specific error information compared to the previous anyhow implementation.

---

`248-252`: **Consistent error handling pattern.**

The error handling for key retrieval follows the same pattern as the database connection error handling, maintaining consistency throughout the codebase.

</details>
<details>
<summary>src/util.rs (1)</summary>

`542-542`: **Updated return type for invoice_subscribe function.**

The function signature has been properly changed from `anyhow::Result<()>` to `Result<(), MostroError>` to align with the PR objective of removing anyhow dependency.

</details>
<details>
<summary>src/bitcoin_price.rs (3)</summary>

`1-2`: **Proper imports for custom error types.**

Good addition of the necessary imports for MostroError and ServiceError to implement the anyhow removal strategy.

---

`23-31`: **Enhanced error handling in update_prices method.**

The method's return type has been correctly changed to `Result<(), MostroError>` and HTTP request error handling has been improved with specific error types, making debugging and error handling more effective.

---

`36-39`: **Consistent error handling for RwLock operations.**

Error handling for RwLock write operations follows the same pattern as other error handling in the file, converting lock errors to ServiceError::IOError.

</details>
<details>
<summary>src/cli/settings.rs (5)</summary>

`3-4`: **Appropriate imports for custom error types.**

Good addition of the necessary imports to implement the anyhow removal strategy across the codebase.

---

`50-54`: **Updated error type for TryFrom implementation.**

The error type for the Database TryFrom implementation has been correctly updated to use MostroError, aligning with the PR objective.

---

`70-74`: **Consistent error type updates across all TryFrom implementations.**

All TryFrom implementations for the different configuration structs (Lightning, Nostr, Mostro) have been updated consistently to use MostroError as the error type.



Also applies to: 84-88, 107-111

---

`173-173`: **Updated function signature for init_default_dir.**

The function signature has been properly updated to return `Result<PathBuf, MostroError>` instead of using anyhow's Result type.

---

`187-189`: **Enhanced error handling with specific error types.**

The error handling in init_default_dir has been improved to use map_err with specific ServiceError variants (EnvVarError, IOError), providing better context for troubleshooting when errors occur.



Also applies to: 204-213

</details>
<details>
<summary>src/db.rs (1)</summary>

`22-73`: **LGTM! Good error handling refactoring.**

The removal of anyhow and introduction of the more specific `MostroError` type improves the API of this module by making the error types explicit in the function signatures.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T11:00:44Z
user: login: grunch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-02T12:48:09Z
user: login: arkanoider
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-02T13:56:59Z
user: login: Catrya
body: tACK
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-03T16:50:29Z
user: login: grunch
body: tACK
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-03T19:58:47Z

Review comments:
diff_hunk: @@ -50,3 +49,6 @@ bitcoin = "0.32.5"
 
 [dev-dependencies]
 tokio = { version = "1.40.0", features = ["full", "test-util", "macros"] }
+
+[patch.crates-io]
+mostro-core = { path = "../mostro-core" }
path: Cargo.toml
user: login: grunch
body: what changes needs mostro core? can you propose a PR there?
created_at: 2025-03-02T12:48:09Z
author_association: MEMBER
diff_hunk: @@ -50,3 +49,6 @@ bitcoin = "0.32.5"
 
 [dev-dependencies]
 tokio = { version = "1.40.0", features = ["full", "test-util", "macros"] }
+
+[patch.crates-io]
+mostro-core = { path = "../mostro-core" }
path: Cargo.toml
user: login: arkanoider
body: sorry wife called and forgot core... fix asap
created_at: 2025-03-02T13:56:59Z
author_association: COLLABORATOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-02T10:58:11Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request refactors error handling across the codebase by removing the dependency on the `anyhow` crate and replacing its usage with a custom error type, `MostroError`. Function signatures in multiple modules have been updated to return `Result<T, MostroError>`, and import statements for `anyhow::Result` have been removed. In addition, the Cargo.toml file now omits the `anyhow` dependency.

## Changes
| Files | Change Summary |
| --- | --- |
| Cargo.toml | Removed external dependency `anyhow = "1.0.89"` and updated `mostro-core` version from `0.6.28` to `0.6.30`. |
| src/app.rs, src/app/add_invoice.rs, src/app/admin_add_solver.rs, src/app/rate_user.rs, src/app/take_buy.rs, src/app/take_sell.rs, src/lightning/mod.rs, src/main.rs, src/messages.rs | Removed `use anyhow::Result` imports; updated error handling in `src/app.rs` to pass a dereferenced error; updated module import paths. |
| src/bitcoin_price.rs, src/cli.rs, src/cli/settings.rs, src/db.rs, src/scheduler.rs, src/util.rs | Changed function signatures from `anyhow::Result` to `Result<…, MostroError>`; enhanced error propagation with structured error mapping (e.g., converting errors via `map_err` into `MostroInternalErr`). |

## Possibly related PRs
- **MostroP2P/mostro#382:** The changes in the main PR, which involve the removal of the `anyhow` dependency and modifications to error handling in various files, are related to the changes in the retrieved PR, specifically in `src/app/add_invoice.rs`, where error handling is also being restructured.
- **MostroP2P/mostro#444:** The changes in the main PR, which involve the removal of the `anyhow` dependency and updates to error handling across various files, are related to the retrieved PR as both involve modifications to error handling mechanisms, specifically transitioning to the `MostroError` type.
- **MostroP2P/mostro#404:** The changes in the main PR, specifically the update of the `mostro-core` dependency version in `Cargo.toml`, are related to the retrieved PR, which also involves a modification to the `mostro-core` dependency version, indicating a direct connection at the code level.

## Poem
> In the code garden, I hop with delight,  
> Leaving `anyhow` behind in the night.  
> With MostroError shining ever so bright,  
> Each function now sings with purpose and might.  
> Hoppy coding, friends, under the moonlight! 🐰✨

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b5d70be376a8e0129f750568be7a25f9aebe4a09 and d17526cbcd95ef93a9b10b9dec8046bec73f9728.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `Cargo.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `Cargo.toml` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* Cargo.toml

</details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- tips_start -->

---

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: arkanoider
created_at: 2025-03-02T15:26:03Z
body: Ok @grunch removed from `cargo.toml`  patch to `mostro-core` 

Mostro core PR [here](https://github.com/MostroP2P/mostro-core/pull/87)
author_association: COLLABORATOR