minreq_client.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. //! Minreq http Client
  2. use async_trait::async_trait;
  3. use cashu::error::ErrorResponse;
  4. use cashu::nuts::{
  5. BlindedMessage, CurrencyUnit, Id, KeySet, KeysResponse, KeysetResponse, MeltBolt11Request,
  6. MeltBolt11Response, MeltQuoteBolt11Request, MeltQuoteBolt11Response, MintBolt11Request,
  7. MintBolt11Response, MintInfo, MintQuoteBolt11Request, MintQuoteBolt11Response, PreMintSecrets,
  8. Proof, SwapRequest, SwapResponse,
  9. };
  10. #[cfg(feature = "nut07")]
  11. use cashu::nuts::{CheckStateRequest, CheckStateResponse};
  12. #[cfg(feature = "nut07")]
  13. use cashu::secret::Secret;
  14. use cashu::{Amount, Bolt11Invoice};
  15. use serde_json::Value;
  16. use tracing::warn;
  17. use url::Url;
  18. use super::join_url;
  19. use crate::client::{Client, Error};
  20. #[derive(Debug, Clone)]
  21. pub struct HttpClient {}
  22. #[async_trait(?Send)]
  23. impl Client for HttpClient {
  24. /// Get Mint Keys [NUT-01]
  25. async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {
  26. let url = join_url(mint_url, &["v1", "keys"])?;
  27. let keys = minreq::get(url).send()?.json::<Value>()?;
  28. let keys: KeysResponse = serde_json::from_str(&keys.to_string())?;
  29. Ok(keys.keysets)
  30. }
  31. /// Get Keyset Keys [NUT-01]
  32. async fn get_mint_keyset(&self, mint_url: Url, keyset_id: Id) -> Result<KeySet, Error> {
  33. let url = join_url(mint_url, &["v1", "keys", &keyset_id.to_string()])?;
  34. let keys = minreq::get(url).send()?.json::<KeysResponse>()?;
  35. // let keys: KeysResponse = serde_json::from_value(keys)?; //
  36. // serde_json::from_str(&keys.to_string())?;
  37. Ok(keys.keysets[0].clone())
  38. }
  39. /// Get Keysets [NUT-02]
  40. async fn get_mint_keysets(&self, mint_url: Url) -> Result<KeysetResponse, Error> {
  41. let url = join_url(mint_url, &["v1", "keysets"])?;
  42. let res = minreq::get(url).send()?.json::<Value>()?;
  43. let response: Result<KeysetResponse, serde_json::Error> =
  44. serde_json::from_value(res.clone());
  45. match response {
  46. Ok(res) => Ok(res),
  47. Err(_) => Err(ErrorResponse::from_json(&res.to_string())?.into()),
  48. }
  49. }
  50. /// Mint Quote [NUT-04]
  51. async fn post_mint_quote(
  52. &self,
  53. mint_url: Url,
  54. amount: Amount,
  55. unit: CurrencyUnit,
  56. ) -> Result<MintQuoteBolt11Response, Error> {
  57. let url = join_url(mint_url, &["v1", "mint", "quote", "bolt11"])?;
  58. let request = MintQuoteBolt11Request { amount, unit };
  59. let res = minreq::post(url).with_json(&request)?.send()?;
  60. let response: Result<MintQuoteBolt11Response, serde_json::Error> =
  61. serde_json::from_value(res.json()?);
  62. match response {
  63. Ok(res) => Ok(res),
  64. Err(_) => {
  65. warn!("Bolt11 Mint Quote Unexpected response: {:?}", res);
  66. Err(ErrorResponse::from_json(&res.status_code.to_string())?.into())
  67. }
  68. }
  69. }
  70. /// Mint Tokens [NUT-04]
  71. async fn post_mint(
  72. &self,
  73. mint_url: Url,
  74. quote: &str,
  75. premint_secrets: PreMintSecrets,
  76. ) -> Result<MintBolt11Response, Error> {
  77. let url = join_url(mint_url, &["v1", "mint", "bolt11"])?;
  78. let request = MintBolt11Request {
  79. quote: quote.to_string(),
  80. outputs: premint_secrets.blinded_messages(),
  81. };
  82. let res = minreq::post(url)
  83. .with_json(&request)?
  84. .send()?
  85. .json::<Value>()?;
  86. let response: Result<MintBolt11Response, serde_json::Error> =
  87. serde_json::from_value(res.clone());
  88. match response {
  89. Ok(res) => Ok(res),
  90. Err(_) => Err(ErrorResponse::from_json(&res.to_string())?.into()),
  91. }
  92. }
  93. /// Melt Quote [NUT-05]
  94. async fn post_melt_quote(
  95. &self,
  96. mint_url: Url,
  97. unit: CurrencyUnit,
  98. request: Bolt11Invoice,
  99. ) -> Result<MeltQuoteBolt11Response, Error> {
  100. let url = join_url(mint_url, &["v1", "melt", "quote", "bolt11"])?;
  101. let request = MeltQuoteBolt11Request { request, unit };
  102. let value = minreq::post(url).with_json(&request)?.send()?;
  103. let value = value.json::<Value>()?;
  104. let response: Result<MeltQuoteBolt11Response, serde_json::Error> =
  105. serde_json::from_value(value.clone());
  106. match response {
  107. Ok(res) => Ok(res),
  108. Err(_) => Err(ErrorResponse::from_json(&value.to_string())?.into()),
  109. }
  110. }
  111. /// Melt [NUT-05]
  112. /// [Nut-08] Lightning fee return if outputs defined
  113. async fn post_melt(
  114. &self,
  115. mint_url: Url,
  116. quote: String,
  117. inputs: Vec<Proof>,
  118. outputs: Option<Vec<BlindedMessage>>,
  119. ) -> Result<MeltBolt11Response, Error> {
  120. let url = join_url(mint_url, &["v1", "melt", "bolt11"])?;
  121. let request = MeltBolt11Request {
  122. quote,
  123. inputs,
  124. outputs,
  125. };
  126. let value = minreq::post(url).with_json(&request)?.send()?;
  127. let value = value.json::<Value>()?;
  128. let response: Result<MeltBolt11Response, serde_json::Error> =
  129. serde_json::from_value(value.clone());
  130. match response {
  131. Ok(res) => Ok(res),
  132. Err(_) => Err(ErrorResponse::from_json(&value.to_string())?.into()),
  133. }
  134. }
  135. /// Split Token [NUT-06]
  136. async fn post_swap(
  137. &self,
  138. mint_url: Url,
  139. split_request: SwapRequest,
  140. ) -> Result<SwapResponse, Error> {
  141. let url = join_url(mint_url, &["v1", "swap"])?;
  142. let res = minreq::post(url).with_json(&split_request)?.send()?;
  143. let value = res.json::<Value>()?;
  144. let response: Result<SwapResponse, serde_json::Error> =
  145. serde_json::from_value(value.clone());
  146. match response {
  147. Ok(res) => Ok(res),
  148. Err(_) => Err(ErrorResponse::from_json(&value.to_string())?.into()),
  149. }
  150. }
  151. /// Spendable check [NUT-07]
  152. #[cfg(feature = "nut07")]
  153. async fn post_check_state(
  154. &self,
  155. mint_url: Url,
  156. secrets: Vec<Secret>,
  157. ) -> Result<CheckStateResponse, Error> {
  158. let url = join_url(mint_url, &["v1", "checkstate"])?;
  159. let request = CheckStateRequest { secrets };
  160. let res = minreq::post(url)
  161. .with_json(&request)?
  162. .send()?
  163. .json::<Value>()?;
  164. let response: Result<CheckStateResponse, serde_json::Error> =
  165. serde_json::from_value(res.clone());
  166. match response {
  167. Ok(res) => Ok(res),
  168. Err(_) => Err(ErrorResponse::from_json(&res.to_string())?.into()),
  169. }
  170. }
  171. /// Get Mint Info [NUT-09]
  172. async fn get_mint_info(&self, mint_url: Url) -> Result<MintInfo, Error> {
  173. let url = join_url(mint_url, &["v1", "info"])?;
  174. let res = minreq::get(url).send()?.json::<Value>()?;
  175. let response: Result<MintInfo, serde_json::Error> = serde_json::from_value(res.clone());
  176. match response {
  177. Ok(res) => Ok(res),
  178. Err(_) => Err(ErrorResponse::from_json(&res.to_string())?.into()),
  179. }
  180. }
  181. }