From 8c78b9aa942914d5ee97d2db60ecd0ed275f17a8 Mon Sep 17 00:00:00 2001 From: thesimplekid Date: Sun, 12 Nov 2023 19:04:24 +0000 Subject: [PATCH] improve: add gloo_wasm client --- crates/cashu-sdk/src/client/gloo_client.rs | 266 +++++++++++++++++++ crates/cashu-sdk/src/client/minreq_client.rs | 2 - crates/cashu-sdk/src/client/mod.rs | 6 +- 3 files changed, 269 insertions(+), 5 deletions(-) create mode 100644 crates/cashu-sdk/src/client/gloo_client.rs diff --git a/crates/cashu-sdk/src/client/gloo_client.rs b/crates/cashu-sdk/src/client/gloo_client.rs new file mode 100644 index 00000000..81702118 --- /dev/null +++ b/crates/cashu-sdk/src/client/gloo_client.rs @@ -0,0 +1,266 @@ +//! gloo wasm http Client + +use async_trait::async_trait; +use cashu::nuts::nut00::wallet::BlindedMessages; +use cashu::nuts::nut00::{BlindedMessage, Proof}; +use cashu::nuts::nut01::Keys; +use cashu::nuts::nut03::RequestMintResponse; +use cashu::nuts::nut04::{MintRequest, PostMintResponse}; +use cashu::nuts::nut05::{CheckFeesRequest, CheckFeesResponse}; +use cashu::nuts::nut06::{SplitRequest, SplitResponse}; +#[cfg(feature = "nut07")] +use cashu::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse}; +use cashu::nuts::nut08::{MeltRequest, MeltResponse}; +#[cfg(feature = "nut09")] +use cashu::nuts::MintInfo; +use cashu::nuts::*; +use cashu::{Amount, Bolt11Invoice}; +use gloo::net::http::Request; +use serde_json::Value; +use url::Url; + +use crate::client::{Client, Error}; + +#[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 { + let url = mint_url.join("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: Keys = serde_json::from_str(&keys.to_string())?; + Ok(keys) + } + + /// Get Keysets [NUT-02] + async fn get_mint_keysets(&self, mint_url: &Url) -> Result { + let url = mint_url.join("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())?), + } + } + + /// Request Mint [NUT-03] + async fn get_request_mint( + &self, + mint_url: &Url, + amount: Amount, + ) -> Result { + let mut url = mint_url.join("mint")?; + url.query_pairs_mut() + .append_pair("amount", &amount.to_sat().to_string()); + + 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 Tokens [NUT-04] + async fn post_mint( + &self, + mint_url: &Url, + blinded_messages: BlindedMessages, + hash: &str, + ) -> Result { + let mut url = mint_url.join("mint")?; + url.query_pairs_mut().append_pair("hash", hash); + + let request = MintRequest { + outputs: blinded_messages.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())?), + } + } + + /// Check Max expected fee [NUT-05] + async fn post_check_fees( + &self, + mint_url: &Url, + invoice: Bolt11Invoice, + ) -> Result { + let url = mint_url.join("checkfees")?; + + let request = CheckFeesRequest { pr: invoice }; + + 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] + /// [Nut-08] Lightning fee return if outputs defined + async fn post_melt( + &self, + mint_url: &Url, + proofs: Vec, + invoice: Bolt11Invoice, + outputs: Option>, + ) -> Result { + let url = mint_url.join("melt")?; + + let request = MeltRequest { + proofs, + pr: invoice, + 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_split( + &self, + mint_url: &Url, + split_request: SplitRequest, + ) -> Result { + let url = mint_url.join("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] + #[cfg(feature = "nut07")] + async fn post_check_spendable( + &self, + mint_url: &Url, + proofs: Vec, + ) -> Result { + let url = mint_url.join("check")?; + let request = CheckSpendableRequest { + proofs: proofs.to_owned(), + }; + + 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] + #[cfg(feature = "nut09")] + async fn get_mint_info(&self, mint_url: &Url) -> Result { + let url = mint_url.join("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())?), + } + } +} diff --git a/crates/cashu-sdk/src/client/minreq_client.rs b/crates/cashu-sdk/src/client/minreq_client.rs index 08b7d93d..2d777f9e 100644 --- a/crates/cashu-sdk/src/client/minreq_client.rs +++ b/crates/cashu-sdk/src/client/minreq_client.rs @@ -15,8 +15,6 @@ use cashu::nuts::nut08::{MeltRequest, MeltResponse}; use cashu::nuts::MintInfo; use cashu::nuts::*; use cashu::{Amount, Bolt11Invoice}; -#[cfg(target_arch = "wasm32")] -use gloo::net::http::Request; use serde_json::Value; use url::Url; diff --git a/crates/cashu-sdk/src/client/mod.rs b/crates/cashu-sdk/src/client/mod.rs index 062e3ca1..c3350662 100644 --- a/crates/cashu-sdk/src/client/mod.rs +++ b/crates/cashu-sdk/src/client/mod.rs @@ -9,18 +9,18 @@ use cashu::nuts::nut04::PostMintResponse; use cashu::nuts::nut05::CheckFeesResponse; use cashu::nuts::nut06::{SplitRequest, SplitResponse}; #[cfg(feature = "nut07")] -use cashu::nuts::nut07::{CheckSpendableRequest, CheckSpendableResponse}; +use cashu::nuts::nut07::CheckSpendableResponse; use cashu::nuts::nut08::MeltResponse; #[cfg(feature = "nut09")] use cashu::nuts::MintInfo; use cashu::nuts::*; use cashu::{utils, Amount}; -#[cfg(target_arch = "wasm32")] -use gloo::net::http::Request; use serde::{Deserialize, Serialize}; use thiserror::Error; use url::Url; +#[cfg(target_arch = "wasm32")] +pub mod gloo_client; #[cfg(not(target_arch = "wasm32"))] pub mod minreq_client;