mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-08 22:55:54 +01:00
refactor: use reqwest client
Using reqwest reduced code duplication since it can be used for both wasm and non wasm targets.
This commit is contained in:
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HttpClient {}
|
||||
fn join_url(url: Url, paths: &[&str]) -> Result<Url, Error> {
|
||||
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 {
|
||||
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<Vec<KeySet>, Error> {
|
||||
pub async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keys"])?;
|
||||
let keys = minreq::get(url).send()?.json::<Value>()?;
|
||||
let keys = self.inner.get(url).send().await?.json::<Value>().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<KeySet, Error> {
|
||||
pub async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keys", &keyset_id.to_string()])?;
|
||||
let keys = minreq::get(url).send()?.json::<KeysResponse>()?;
|
||||
let keys = self
|
||||
.inner
|
||||
.get(url)
|
||||
.send()
|
||||
.await?
|
||||
.json::<KeysResponse>()
|
||||
.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<KeysetResponse, Error> {
|
||||
pub async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "keysets"])?;
|
||||
let res = minreq::get(url).send()?.json::<Value>()?;
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
let response: Result<KeysetResponse, serde_json::Error> =
|
||||
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<MintQuoteBolt11Response, serde_json::Error> =
|
||||
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::<Value>()?;
|
||||
let res = self
|
||||
.inner
|
||||
.post(url)
|
||||
.json(&request)
|
||||
.send()
|
||||
.await?
|
||||
.json::<Value>()
|
||||
.await?;
|
||||
|
||||
let response: Result<MintBolt11Response, serde_json::Error> =
|
||||
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::<Value>()?;
|
||||
let value = value.json::<Value>().await?;
|
||||
|
||||
let response: Result<MeltQuoteBolt11Response, serde_json::Error> =
|
||||
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::<Value>()?;
|
||||
let value = value.json::<Value>().await?;
|
||||
let response: Result<MeltBolt11Response, serde_json::Error> =
|
||||
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<SwapResponse, Error> {
|
||||
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::<Value>()?;
|
||||
let value = res.json::<Value>().await?;
|
||||
let response: Result<SwapResponse, serde_json::Error> =
|
||||
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<MintInfo, Error> {
|
||||
pub async fn get_mint_info(&self, mint_url: Url) -> Result<MintInfo, Error> {
|
||||
let url = join_url(mint_url, &["v1", "info"])?;
|
||||
|
||||
let res = minreq::get(url).send()?.json::<Value>()?;
|
||||
let res = self.inner.get(url).send().await?.json::<Value>().await?;
|
||||
|
||||
let response: Result<MintInfo, serde_json::Error> = 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<PublicKey>,
|
||||
@@ -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::<Value>()?;
|
||||
let res = self
|
||||
.inner
|
||||
.post(url)
|
||||
.json(&request)
|
||||
.send()
|
||||
.await?
|
||||
.json::<Value>()
|
||||
.await?;
|
||||
|
||||
let response: Result<CheckStateResponse, serde_json::Error> =
|
||||
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<RestoreResponse, Error> {
|
||||
let url = join_url(mint_url, &["v1", "restore"])?;
|
||||
|
||||
let res = minreq::post(url)
|
||||
.with_json(&request)?
|
||||
.send()?
|
||||
.json::<Value>()?;
|
||||
let res = self
|
||||
.inner
|
||||
.post(url)
|
||||
.json(&request)
|
||||
.send()
|
||||
.await?
|
||||
.json::<Value>()
|
||||
.await?;
|
||||
|
||||
let response: Result<RestoreResponse, serde_json::Error> =
|
||||
serde_json::from_value(res.clone());
|
||||
@@ -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<Vec<KeySet>, 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::<Value>()
|
||||
.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<KeysetResponse, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<KeysetResponse, serde_json::Error> =
|
||||
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<MintQuoteBolt11Response, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MintQuoteBolt11Response, serde_json::Error> =
|
||||
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<MintBolt11Response, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MintBolt11Response, serde_json::Error> =
|
||||
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<MeltQuoteBolt11Response, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MeltQuoteBolt11Response, serde_json::Error> =
|
||||
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<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltBolt11Response, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MeltBolt11Response, serde_json::Error> =
|
||||
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<SwapResponse, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<SwapResponse, serde_json::Error> = 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<PublicKey>,
|
||||
) -> Result<CheckStateResponse, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<CheckSpendableResponse, serde_json::Error> =
|
||||
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<MintInfo, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<MintInfo, serde_json::Error> = 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<CheckStateResponse, Error> {
|
||||
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::<Value>()
|
||||
.await
|
||||
.map_err(|err| Error::Gloo(err.to_string()))?;
|
||||
|
||||
let response: Result<RestoreRequest, serde_json::Error> =
|
||||
serde_json::from_value(res.clone());
|
||||
|
||||
match response {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Err(Error::from_json(&res.to_string())?),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String>),
|
||||
/// 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<ErrorResponse> 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<Vec<KeySet>, Error>;
|
||||
|
||||
async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error>;
|
||||
|
||||
async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error>;
|
||||
|
||||
async fn post_mint_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
amount: Amount,
|
||||
unit: CurrencyUnit,
|
||||
) -> Result<MintQuoteBolt11Response, Error>;
|
||||
|
||||
async fn post_mint(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
quote: &str,
|
||||
premint_secrets: PreMintSecrets,
|
||||
) -> Result<MintBolt11Response, Error>;
|
||||
|
||||
async fn post_melt_quote(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
unit: CurrencyUnit,
|
||||
request: Bolt11Invoice,
|
||||
) -> Result<MeltQuoteBolt11Response, Error>;
|
||||
|
||||
async fn post_melt(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
quote: String,
|
||||
inputs: Vec<Proof>,
|
||||
outputs: Option<Vec<BlindedMessage>>,
|
||||
) -> Result<MeltBolt11Response, Error>;
|
||||
|
||||
// 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<SwapResponse, Error>;
|
||||
|
||||
async fn post_check_state(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
ys: Vec<PublicKey>,
|
||||
) -> Result<CheckStateResponse, Error>;
|
||||
|
||||
async fn get_mint_info(&self, mint_url: Url) -> Result<MintInfo, Error>;
|
||||
|
||||
async fn post_restore(
|
||||
&self,
|
||||
mint_url: Url,
|
||||
restore_request: RestoreRequest,
|
||||
) -> Result<RestoreResponse, Error>;
|
||||
}
|
||||
|
||||
#[cfg(any(not(target_arch = "wasm32"), feature = "gloo"))]
|
||||
fn join_url(url: Url, paths: &[&str]) -> Result<Url, Error> {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -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<ErrorResponse> for Error {
|
||||
fn from(err: ErrorResponse) -> Error {
|
||||
Self::UnknownErrorResponse(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<dyn Client + Send + Sync>,
|
||||
pub client: HttpClient,
|
||||
pub localstore: Arc<dyn LocalStore + Send + Sync>,
|
||||
mnemonic: Option<Mnemonic>,
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
pub async fn new(
|
||||
client: Arc<dyn Client + Sync + Send>,
|
||||
client: HttpClient,
|
||||
localstore: Arc<dyn LocalStore + Send + Sync>,
|
||||
mnemonic: Option<Mnemonic>,
|
||||
) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user