From 391692e33248f92684d1ac0beced2b27ec03a145 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Fri, 12 Apr 2024 22:00:32 +0100 Subject: [PATCH] refactor: use reqwest client Using reqwest reduced code duplication since it can be used for both wasm and non wasm targets. --- .github/workflows/ci.yml | 3 + crates/cdk/Cargo.toml | 6 +- .../{client/minreq_client.rs => client.rs} | 141 ++++++--- crates/cdk/src/client/gloo_client.rs | 282 ------------------ crates/cdk/src/client/mod.rs | 164 ---------- crates/cdk/src/error/mod.rs | 13 + crates/cdk/src/wallet/mod.rs | 8 +- 7 files changed, 113 insertions(+), 504 deletions(-) rename crates/cdk/src/{client/minreq_client.rs => client.rs} (65%) delete mode 100644 crates/cdk/src/client/gloo_client.rs delete mode 100644 crates/cdk/src/client/mod.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55219c89..cfb86f47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,6 +63,9 @@ jobs: build-args: [ -p cdk, + -p cdk --no-default-features, + -p cdk --no-default-features --features wallet, + -p cdk --no-default-features --features all-nuts, ] steps: - name: Checkout diff --git a/crates/cdk/Cargo.toml b/crates/cdk/Cargo.toml index fd47e733..2c8a662e 100644 --- a/crates/cdk/Cargo.toml +++ b/crates/cdk/Cargo.toml @@ -12,8 +12,7 @@ license.workspace = true [features] default = ["mint", "wallet", "all-nuts", "redb"] mint = ["dep:bip39"] -wallet = ["nut13", "dep:minreq", "dep:bip39"] -gloo = ["dep:gloo"] +wallet = ["nut13", "dep:bip39", "dep:reqwest"] all-nuts = ["nut13"] nut13 = ["dep:bip39"] redb = ["dep:redb"] @@ -32,13 +31,12 @@ url = "2.3.1" tracing = { version = "0.1", default-features = false } thiserror = "1.0.50" async-trait = "0.1.74" -gloo = { version = "0.11.0", optional = true, features = ["net"] } http = "1.0.0" uuid = { version = "1.6", features = ["v4"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "socks"], optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "time", "macros", "sync"] } -minreq = { version = "2.7.0", optional = true, features = ["json-using-serde", "https"] } redb = { version = "2.0.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/crates/cdk/src/client/minreq_client.rs b/crates/cdk/src/client.rs similarity index 65% rename from crates/cdk/src/client/minreq_client.rs rename to crates/cdk/src/client.rs index 2d21b928..9c5960bd 100644 --- a/crates/cdk/src/client/minreq_client.rs +++ b/crates/cdk/src/client.rs @@ -1,13 +1,8 @@ -//! Minreq http Client - -use async_trait::async_trait; +use reqwest::Client; use serde_json::Value; -use tracing::warn; use url::Url; -use super::join_url; -use crate::client::{Client, Error}; -use crate::error::ErrorResponse; +use crate::error::{Error, ErrorResponse}; use crate::nuts::{ BlindedMessage, CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request, MeltBolt11Response, MeltQuoteBolt11Request, @@ -17,24 +12,61 @@ use crate::nuts::{ }; use crate::{Amount, Bolt11Invoice}; +fn join_url(url: Url, paths: &[&str]) -> Result { + let mut url = url; + for path in paths { + if !url.path().ends_with('/') { + url.path_segments_mut() + .map_err(|_| Error::CustomError("Url Path Segmants".to_string()))? + .push(path); + } else { + url.path_segments_mut() + .map_err(|_| Error::CustomError("Url Path Segmants".to_string()))? + .pop() + .push(path); + } + } + + Ok(url) +} + #[derive(Debug, Clone)] -pub struct HttpClient {} +pub struct HttpClient { + inner: Client, +} + +impl Default for HttpClient { + fn default() -> Self { + Self::new() + } +} + +impl HttpClient { + pub fn new() -> Self { + Self { + inner: Client::new(), + } + } -#[async_trait(?Send)] -impl Client for HttpClient { /// Get Active Mint Keys [NUT-01] - async fn get_mint_keys(&self, mint_url: Url) -> Result, Error> { + pub async fn get_mint_keys(&self, mint_url: Url) -> Result, Error> { let url = join_url(mint_url, &["v1", "keys"])?; - let keys = minreq::get(url).send()?.json::()?; + let keys = self.inner.get(url).send().await?.json::().await?; let keys: KeysResponse = serde_json::from_value(keys)?; Ok(keys.keysets) } /// Get Keyset Keys [NUT-01] - async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result { + pub async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result { let url = join_url(mint_url, &["v1", "keys", &keyset_id.to_string()])?; - let keys = minreq::get(url).send()?.json::()?; + let keys = self + .inner + .get(url) + .send() + .await? + .json::() + .await?; // let keys: KeysResponse = serde_json::from_value(keys)?; // // serde_json::from_str(&keys.to_string())?; @@ -42,9 +74,9 @@ impl Client for HttpClient { } /// Get Keysets [NUT-02] - async fn get_mint_keysets(&self, mint_url: Url) -> Result { + pub async fn get_mint_keysets(&self, mint_url: Url) -> Result { let url = join_url(mint_url, &["v1", "keysets"])?; - let res = minreq::get(url).send()?.json::()?; + let res = self.inner.get(url).send().await?.json::().await?; let response: Result = serde_json::from_value(res.clone()); @@ -56,7 +88,7 @@ impl Client for HttpClient { } /// Mint Quote [NUT-04] - async fn post_mint_quote( + pub async fn post_mint_quote( &self, mint_url: Url, amount: Amount, @@ -66,22 +98,21 @@ impl Client for HttpClient { let request = MintQuoteBolt11Request { amount, unit }; - let res = minreq::post(url).with_json(&request)?.send()?; + let res = self.inner.post(url).json(&request).send().await?; + + let status = res.status(); let response: Result = - serde_json::from_value(res.json()?); + serde_json::from_value(res.json().await?); match response { Ok(res) => Ok(res), - Err(_) => { - warn!("Bolt11 Mint Quote Unexpected response: {:?}", res); - Err(ErrorResponse::from_json(&res.status_code.to_string())?.into()) - } + Err(_) => Err(ErrorResponse::from_json(&status.to_string())?.into()), } } /// Mint Tokens [NUT-04] - async fn post_mint( + pub async fn post_mint( &self, mint_url: Url, quote: &str, @@ -94,10 +125,14 @@ impl Client for HttpClient { outputs: premint_secrets.blinded_messages(), }; - let res = minreq::post(url) - .with_json(&request)? - .send()? - .json::()?; + let res = self + .inner + .post(url) + .json(&request) + .send() + .await? + .json::() + .await?; let response: Result = serde_json::from_value(res.clone()); @@ -109,7 +144,7 @@ impl Client for HttpClient { } /// Melt Quote [NUT-05] - async fn post_melt_quote( + pub async fn post_melt_quote( &self, mint_url: Url, unit: CurrencyUnit, @@ -119,9 +154,9 @@ impl Client for HttpClient { let request = MeltQuoteBolt11Request { request, unit }; - let value = minreq::post(url).with_json(&request)?.send()?; + let value = self.inner.post(url).json(&request).send().await?; - let value = value.json::()?; + let value = value.json::().await?; let response: Result = serde_json::from_value(value.clone()); @@ -134,7 +169,7 @@ impl Client for HttpClient { /// Melt [NUT-05] /// [Nut-08] Lightning fee return if outputs defined - async fn post_melt( + pub async fn post_melt( &self, mint_url: Url, quote: String, @@ -149,9 +184,9 @@ impl Client for HttpClient { outputs, }; - let value = minreq::post(url).with_json(&request)?.send()?; + let value = self.inner.post(url).json(&request).send().await?; - let value = value.json::()?; + let value = value.json::().await?; let response: Result = serde_json::from_value(value.clone()); @@ -162,16 +197,16 @@ impl Client for HttpClient { } /// Split Token [NUT-06] - async fn post_swap( + pub async fn post_swap( &self, mint_url: Url, swap_request: SwapRequest, ) -> Result { let url = join_url(mint_url, &["v1", "swap"])?; - let res = minreq::post(url).with_json(&swap_request)?.send()?; + let res = self.inner.post(url).json(&swap_request).send().await?; - let value = res.json::()?; + let value = res.json::().await?; let response: Result = serde_json::from_value(value.clone()); @@ -182,10 +217,10 @@ impl Client for HttpClient { } /// Get Mint Info [NUT-06] - async fn get_mint_info(&self, mint_url: Url) -> Result { + pub async fn get_mint_info(&self, mint_url: Url) -> Result { let url = join_url(mint_url, &["v1", "info"])?; - let res = minreq::get(url).send()?.json::()?; + let res = self.inner.get(url).send().await?.json::().await?; let response: Result = serde_json::from_value(res.clone()); @@ -196,7 +231,7 @@ impl Client for HttpClient { } /// Spendable check [NUT-07] - async fn post_check_state( + pub async fn post_check_state( &self, mint_url: Url, ys: Vec, @@ -204,10 +239,14 @@ impl Client for HttpClient { let url = join_url(mint_url, &["v1", "checkstate"])?; let request = CheckStateRequest { ys }; - let res = minreq::post(url) - .with_json(&request)? - .send()? - .json::()?; + let res = self + .inner + .post(url) + .json(&request) + .send() + .await? + .json::() + .await?; let response: Result = serde_json::from_value(res.clone()); @@ -218,17 +257,21 @@ impl Client for HttpClient { } } - async fn post_restore( + pub async fn post_restore( &self, mint_url: Url, request: RestoreRequest, ) -> Result { let url = join_url(mint_url, &["v1", "restore"])?; - let res = minreq::post(url) - .with_json(&request)? - .send()? - .json::()?; + let res = self + .inner + .post(url) + .json(&request) + .send() + .await? + .json::() + .await?; let response: Result = serde_json::from_value(res.clone()); diff --git a/crates/cdk/src/client/gloo_client.rs b/crates/cdk/src/client/gloo_client.rs deleted file mode 100644 index 3d226ad8..00000000 --- a/crates/cdk/src/client/gloo_client.rs +++ /dev/null @@ -1,282 +0,0 @@ -//! gloo wasm http Client - -use async_trait::async_trait; -use gloo::net::http::Request; -use serde_json::Value; -use url::Url; - -use super::join_url; -use crate::client::{Client, Error}; -use crate::nuts::{ - BlindedMessage, CheckSpendableRequest, CheckSpendableResponse, MeltBolt11Request, - MeltBolt11Response, MintBolt11Request, MintBolt11Response, MintInfo, PreMintSecrets, Proof, - PublicKey, RestoreRequest, RestoreResponse, SwapRequest, SwapResponse, *, -}; -use crate::{Amount, Bolt11Invoice}; - -#[derive(Debug, Clone)] -pub struct HttpClient {} - -#[async_trait(?Send)] -impl Client for HttpClient { - /// Get Mint Keys [NUT-01] - async fn get_mint_keys(&self, mint_url: Url) -> Result, Error> { - let url = join_url(mint_url, &["v1", "keys"])?; - let keys = Request::get(url.as_str()) - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let keys: KeysResponse = serde_json::from_str(&keys.to_string())?; - Ok(keys.keysets) - } - - /// Get Keysets [NUT-02] - async fn get_mint_keysets(&self, mint_url: Url) -> Result { - let url = join_url(mint_url, &["v1", "keysets"])?; - let res = Request::get(url.as_str()) - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Mint Quote [NUT-04] - async fn post_mint_quote( - &self, - mint_url: Url, - amount: Amount, - unit: CurrencyUnit, - ) -> Result { - let url = join_url(mint_url, &["v1", "mint", "quote", "bolt11"])?; - - let request = MintQuoteBolt11Request { amount, unit }; - let res = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Mint Tokens [NUT-04] - async fn post_mint( - &self, - mint_url: Url, - quote: &str, - premint_secrets: PreMintSecrets, - ) -> Result { - let url = join_url(mint_url, &["v1", "mint", "bolt11"])?; - - let request = MintBolt11Request { - quote: quote.to_string(), - outputs: premint_secrets.blinded_messages(), - }; - - let res = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Melt [NUT-05] - async fn post_melt_quote( - &self, - mint_url: Url, - unit: CurrencyUnit, - request: Bolt11Invoice, - ) -> Result { - let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?; - - let request = MeltQuoteBolt11Request { unit, request }; - let res = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// [Nut-08] Lightning fee return if outputs defined - async fn post_melt( - &self, - mint_url: Url, - quote: String, - inputs: Vec, - outputs: Option>, - ) -> Result { - let url = join_url(mint_url, &["v1", "melt", "bolt11"])?; - - let request = MeltBolt11Request { - quote, - inputs, - outputs, - }; - - let value = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(value.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&value.to_string())?), - } - } - - /// Split Token [NUT-06] - async fn post_swap( - &self, - mint_url: Url, - split_request: SwapRequest, - ) -> Result { - let url = join_url(mint_url, &["v1", "split"])?; - - let res = Request::post(url.as_str()) - .json(&split_request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Spendable check [NUT-07] - async fn post_check_state( - &self, - mint_url: Url, - ys: Vec, - ) -> Result { - let url = join_url(mint_url, &["v1", "check"])?; - let request = CheckSpendableRequest { ys }; - - let res = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Get Mint Info [NUT-09] - async fn get_mint_info(&self, mint_url: Url) -> Result { - let url = join_url(mint_url, &["v1", "info"])?; - let res = Request::get(url.as_str()) - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } - - /// Restore [NUT-09] - async fn post_check_state( - &self, - mint_url: Url, - request: RestoreRequest, - ) -> Result { - let url = join_url(mint_url, &["v1", "check"])?; - - let res = Request::post(url.as_str()) - .json(&request) - .map_err(|err| Error::Gloo(err.to_string()))? - .send() - .await - .map_err(|err| Error::Gloo(err.to_string()))? - .json::() - .await - .map_err(|err| Error::Gloo(err.to_string()))?; - - let response: Result = - serde_json::from_value(res.clone()); - - match response { - Ok(res) => Ok(res), - Err(_) => Err(Error::from_json(&res.to_string())?), - } - } -} diff --git a/crates/cdk/src/client/mod.rs b/crates/cdk/src/client/mod.rs deleted file mode 100644 index 8ba896c1..00000000 --- a/crates/cdk/src/client/mod.rs +++ /dev/null @@ -1,164 +0,0 @@ -//! Client to connet to mint - -use async_trait::async_trait; -use thiserror::Error; -use url::Url; - -use crate::error::ErrorResponse; -use crate::nuts::nut09::{RestoreRequest, RestoreResponse}; -use crate::nuts::{ - BlindedMessage, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysetResponse, - MeltBolt11Response, MeltQuoteBolt11Response, MintBolt11Response, MintInfo, - MintQuoteBolt11Response, PreMintSecrets, Proof, PublicKey, SwapRequest, SwapResponse, -}; -use crate::Amount; - -#[cfg(feature = "gloo")] -pub mod gloo_client; -#[cfg(not(target_arch = "wasm32"))] -pub mod minreq_client; - -pub use crate::Bolt11Invoice; - -#[derive(Debug, Error)] -pub enum Error { - #[error("Invoice not paid")] - InvoiceNotPaid, - #[error("Wallet not responding")] - LightingWalletNotResponding(Option), - /// Parse Url Error - #[error("`{0}`")] - UrlParse(#[from] url::ParseError), - /// Serde Json error - #[error("`{0}`")] - SerdeJson(#[from] serde_json::Error), - /// Cashu Url Error - #[error("`{0}`")] - CashuUrl(#[from] crate::url::Error), - /// Min req error - #[cfg(not(target_arch = "wasm32"))] - #[error("`{0}`")] - MinReq(#[from] minreq::Error), - #[cfg(feature = "gloo")] - #[error("`{0}`")] - Gloo(String), - #[error("Unknown Error response")] - UnknownErrorResponse(crate::error::ErrorResponse), - /// Custom Error - #[error("`{0}`")] - Custom(String), -} - -impl From for Error { - fn from(err: ErrorResponse) -> Error { - Self::UnknownErrorResponse(err) - } -} - -#[async_trait(?Send)] -pub trait Client { - async fn get_mint_keys(&self, mint_url: Url) -> Result, Error>; - - async fn get_mint_keysets(&self, mint_url: Url) -> Result; - - async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result; - - async fn post_mint_quote( - &self, - mint_url: Url, - amount: Amount, - unit: CurrencyUnit, - ) -> Result; - - async fn post_mint( - &self, - mint_url: Url, - quote: &str, - premint_secrets: PreMintSecrets, - ) -> Result; - - async fn post_melt_quote( - &self, - mint_url: Url, - unit: CurrencyUnit, - request: Bolt11Invoice, - ) -> Result; - - async fn post_melt( - &self, - mint_url: Url, - quote: String, - inputs: Vec, - outputs: Option>, - ) -> Result; - - // REVIEW: Should be consistent aboue passing in the Request struct or the - // compnatants and making it within the function. Here the struct is passed - // in but in check spendable and melt the compants are passed in - async fn post_swap( - &self, - mint_url: Url, - split_request: SwapRequest, - ) -> Result; - - async fn post_check_state( - &self, - mint_url: Url, - ys: Vec, - ) -> Result; - - async fn get_mint_info(&self, mint_url: Url) -> Result; - - async fn post_restore( - &self, - mint_url: Url, - restore_request: RestoreRequest, - ) -> Result; -} - -#[cfg(any(not(target_arch = "wasm32"), feature = "gloo"))] -fn join_url(url: Url, paths: &[&str]) -> Result { - let mut url = url; - for path in paths { - if !url.path().ends_with('/') { - url.path_segments_mut() - .map_err(|_| Error::Custom("Url Path Segmants".to_string()))? - .push(path); - } else { - url.path_segments_mut() - .map_err(|_| Error::Custom("Url Path Segmants".to_string()))? - .pop() - .push(path); - } - } - - Ok(url) -} - -#[cfg(test)] -mod tests { - /* - use super::*; - - #[test] - fn test_decode_error() { - let err = r#"{"code":0,"error":"Lightning invoice not paid yet."}"#; - - let error = Error::from_json(err).unwrap(); - - match error { - Error::InvoiceNotPaid => {} - _ => panic!("Wrong error"), - } - - let err = r#"{"code": 0, "error": "Lightning wallet not responding: Failed to connect to https://legend.lnbits.com due to: All connection attempts failed"}"#; - let error = Error::from_json(err).unwrap(); - match error { - Error::LightingWalletNotResponding(mint) => { - assert_eq!(mint, Some("https://legend.lnbits.com".to_string())); - } - _ => panic!("Wrong error"), - } - } - */ -} diff --git a/crates/cdk/src/error/mod.rs b/crates/cdk/src/error/mod.rs index 4c34b81e..e9a03d65 100644 --- a/crates/cdk/src/error/mod.rs +++ b/crates/cdk/src/error/mod.rs @@ -58,6 +58,10 @@ pub enum Error { /// From hex error #[error(transparent)] HexError(#[from] hex::Error), + #[cfg(feature = "wallet")] + /// From hex error + #[error(transparent)] + HReeqwestError(#[from] reqwest::Error), /// Nut01 error #[error(transparent)] NUT01(#[from] crate::nuts::nut01::Error), @@ -67,6 +71,9 @@ pub enum Error { /// NUT11 Error #[error(transparent)] NUT11(#[from] crate::nuts::nut11::Error), + /// Min req error + #[error("Unknown Error response")] + UnknownErrorResponse(crate::error::ErrorResponse), /// Custom error #[error("`{0}`")] CustomError(String), @@ -92,3 +99,9 @@ impl ErrorResponse { } } } + +impl From for Error { + fn from(err: ErrorResponse) -> Error { + Self::UnknownErrorResponse(err) + } +} diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index f286b3af..54f05b95 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -9,7 +9,7 @@ use localstore::LocalStore; use thiserror::Error; use tracing::{debug, warn}; -use crate::client::Client; +use crate::client::HttpClient; use crate::dhke::{construct_proofs, hash_to_curve, unblind_message}; use crate::nuts::{ BlindSignature, CurrencyUnit, Id, KeySet, KeySetInfo, Keys, MintInfo, P2PKConditions, @@ -48,8 +48,6 @@ pub enum Error { UnknownKey, #[error(transparent)] ParseInt(#[from] ParseIntError), - #[error(transparent)] - Client(#[from] crate::client::Error), /// Cashu Url Error #[error(transparent)] CashuUrl(#[from] crate::url::Error), @@ -65,14 +63,14 @@ pub enum Error { #[derive(Clone)] pub struct Wallet { - pub client: Arc, + pub client: HttpClient, pub localstore: Arc, mnemonic: Option, } impl Wallet { pub async fn new( - client: Arc, + client: HttpClient, localstore: Arc, mnemonic: Option, ) -> Self {