wallet.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. use std::ops::Deref;
  2. use std::str::FromStr;
  3. use std::sync::Arc;
  4. use cdk::nuts::{Proofs, SigningKey};
  5. use cdk::url::UncheckedUrl;
  6. use cdk::wallet::Wallet;
  7. use cdk::{Amount, HttpClient};
  8. use cdk_rexie::RexieWalletDatabase;
  9. use wasm_bindgen::prelude::*;
  10. use crate::error::{into_err, Result};
  11. use crate::nuts::nut04::JsMintQuoteBolt11Response;
  12. use crate::nuts::nut05::JsMeltQuoteBolt11Response;
  13. use crate::nuts::nut11::JsP2PKSpendingConditions;
  14. use crate::nuts::nut14::JsHTLCSpendingConditions;
  15. use crate::nuts::{JsCurrencyUnit, JsMintInfo, JsProof};
  16. use crate::types::melt_quote::JsMeltQuote;
  17. use crate::types::{JsAmount, JsMelted, JsMintQuote};
  18. #[wasm_bindgen(js_name = Wallet)]
  19. pub struct JsWallet {
  20. inner: Wallet,
  21. }
  22. impl Deref for JsWallet {
  23. type Target = Wallet;
  24. fn deref(&self) -> &Self::Target {
  25. &self.inner
  26. }
  27. }
  28. impl From<Wallet> for JsWallet {
  29. fn from(inner: Wallet) -> JsWallet {
  30. JsWallet { inner }
  31. }
  32. }
  33. #[wasm_bindgen(js_class = Wallet)]
  34. impl JsWallet {
  35. #[wasm_bindgen(constructor)]
  36. pub async fn new(seed: Vec<u8>) -> Self {
  37. let client = HttpClient::new();
  38. let db = RexieWalletDatabase::new().await.unwrap();
  39. Wallet::new(client, Arc::new(db), &seed).await.into()
  40. }
  41. #[wasm_bindgen(js_name = totalBalance)]
  42. pub async fn total_balance(&self) -> Result<JsAmount> {
  43. Ok(self.inner.total_balance().await.map_err(into_err)?.into())
  44. }
  45. #[wasm_bindgen(js_name = mintBalances)]
  46. pub async fn mint_balances(&self) -> Result<JsValue> {
  47. let mint_balances = self.inner.mint_balances().await.map_err(into_err)?;
  48. Ok(serde_wasm_bindgen::to_value(&mint_balances)?)
  49. }
  50. #[wasm_bindgen(js_name = addMint)]
  51. pub async fn add_mint(&self, mint_url: String) -> Result<Option<JsMintInfo>> {
  52. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  53. Ok(self
  54. .inner
  55. .add_mint(mint_url)
  56. .await
  57. .map_err(into_err)?
  58. .map(|i| i.into()))
  59. }
  60. #[wasm_bindgen(js_name = refreshMint)]
  61. pub async fn refresh_mint_keys(&self, mint_url: String) -> Result<()> {
  62. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  63. self.inner
  64. .refresh_mint_keys(&mint_url)
  65. .await
  66. .map_err(into_err)?;
  67. Ok(())
  68. }
  69. #[wasm_bindgen(js_name = mintQuote)]
  70. pub async fn mint_quote(
  71. &mut self,
  72. mint_url: String,
  73. amount: u64,
  74. unit: JsCurrencyUnit,
  75. ) -> Result<JsMintQuote> {
  76. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  77. let quote = self
  78. .inner
  79. .mint_quote(mint_url, amount.into(), unit.into())
  80. .await
  81. .map_err(into_err)?;
  82. Ok(quote.into())
  83. }
  84. #[wasm_bindgen(js_name = mintQuoteStatus)]
  85. pub async fn mint_quote_status(
  86. &self,
  87. mint_url: String,
  88. quote_id: String,
  89. ) -> Result<JsMintQuoteBolt11Response> {
  90. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  91. let quote = self
  92. .inner
  93. .mint_quote_status(mint_url, &quote_id)
  94. .await
  95. .map_err(into_err)?;
  96. Ok(quote.into())
  97. }
  98. #[wasm_bindgen(js_name = mint)]
  99. pub async fn mint(&mut self, mint_url: String, quote_id: String) -> Result<JsAmount> {
  100. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  101. Ok(self
  102. .inner
  103. .mint(mint_url, &quote_id)
  104. .await
  105. .map_err(into_err)?
  106. .into())
  107. }
  108. #[wasm_bindgen(js_name = meltQuote)]
  109. pub async fn melt_quote(
  110. &mut self,
  111. mint_url: String,
  112. unit: JsCurrencyUnit,
  113. request: String,
  114. ) -> Result<JsMeltQuote> {
  115. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  116. let melt_quote = self
  117. .inner
  118. .melt_quote(mint_url, unit.into(), request)
  119. .await
  120. .map_err(into_err)?;
  121. Ok(melt_quote.into())
  122. }
  123. #[wasm_bindgen(js_name = meltQuoteStatus)]
  124. pub async fn melt_quote_status(
  125. &self,
  126. mint_url: String,
  127. quote_id: String,
  128. ) -> Result<JsMeltQuoteBolt11Response> {
  129. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  130. let quote = self
  131. .inner
  132. .melt_quote_status(mint_url, &quote_id)
  133. .await
  134. .map_err(into_err)?;
  135. Ok(quote.into())
  136. }
  137. #[wasm_bindgen(js_name = melt)]
  138. pub async fn melt(&mut self, mint_url: String, quote_id: String) -> Result<JsMelted> {
  139. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  140. let melted = self
  141. .inner
  142. .melt(&mint_url, &quote_id)
  143. .await
  144. .map_err(into_err)?;
  145. Ok(melted.into())
  146. }
  147. #[wasm_bindgen(js_name = receive)]
  148. pub async fn receive(
  149. &mut self,
  150. encoded_token: String,
  151. signing_keys: JsValue,
  152. preimages: JsValue,
  153. ) -> Result<()> {
  154. let signing_keys: Option<Vec<SigningKey>> = serde_wasm_bindgen::from_value(signing_keys)?;
  155. let preimages: Option<Vec<String>> = serde_wasm_bindgen::from_value(preimages)?;
  156. self.inner
  157. .receive(&encoded_token, signing_keys, preimages)
  158. .await
  159. .map_err(into_err)?;
  160. Ok(())
  161. }
  162. #[wasm_bindgen(js_name = send)]
  163. pub async fn send(
  164. &mut self,
  165. mint_url: String,
  166. unit: JsCurrencyUnit,
  167. memo: Option<String>,
  168. amount: u64,
  169. p2pk_condition: Option<JsP2PKSpendingConditions>,
  170. htlc_condition: Option<JsHTLCSpendingConditions>,
  171. ) -> Result<String> {
  172. let conditions = match (p2pk_condition, htlc_condition) {
  173. (Some(_), Some(_)) => {
  174. return Err(JsValue::from_str(
  175. "Cannot define both p2pk and htlc conditions",
  176. ));
  177. }
  178. (None, Some(htlc_condition)) => Some(htlc_condition.deref().clone()),
  179. (Some(p2pk_condition), None) => Some(p2pk_condition.deref().clone()),
  180. (None, None) => None,
  181. };
  182. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  183. self.inner
  184. .send(
  185. &mint_url,
  186. &unit.into(),
  187. memo,
  188. Amount::from(amount),
  189. conditions,
  190. )
  191. .await
  192. .map_err(into_err)
  193. }
  194. #[wasm_bindgen(js_name = swap)]
  195. pub async fn swap(
  196. &mut self,
  197. mint_url: String,
  198. unit: JsCurrencyUnit,
  199. amount: u64,
  200. input_proofs: Vec<JsProof>,
  201. p2pk_condition: Option<JsP2PKSpendingConditions>,
  202. htlc_condition: Option<JsHTLCSpendingConditions>,
  203. ) -> Result<JsValue> {
  204. let conditions = match (p2pk_condition, htlc_condition) {
  205. (Some(_), Some(_)) => {
  206. return Err(JsValue::from_str(
  207. "Cannot define both p2pk and htlc conditions",
  208. ));
  209. }
  210. (None, Some(htlc_condition)) => Some(htlc_condition.deref().clone()),
  211. (Some(p2pk_condition), None) => Some(p2pk_condition.deref().clone()),
  212. (None, None) => None,
  213. };
  214. let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;
  215. let proofs: Proofs = input_proofs.iter().map(|p| p.deref()).cloned().collect();
  216. let post_swap_proofs = self
  217. .inner
  218. .swap(
  219. &mint_url,
  220. &unit.into(),
  221. Some(Amount::from(amount)),
  222. proofs,
  223. conditions,
  224. )
  225. .await
  226. .map_err(into_err)?;
  227. Ok(serde_wasm_bindgen::to_value(&post_swap_proofs)?)
  228. }
  229. }