| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 | use std::ops::Deref;use std::str::FromStr;use std::sync::Arc;use cdk::amount::SplitTarget;use cdk::nuts::{Proofs, SecretKey};use cdk::url::UncheckedUrl;use cdk::wallet::Wallet;use cdk::Amount;use cdk_rexie::RexieWalletDatabase;use wasm_bindgen::prelude::*;use crate::error::{into_err, Result};use crate::nuts::nut04::JsMintQuoteBolt11Response;use crate::nuts::nut05::JsMeltQuoteBolt11Response;use crate::nuts::nut11::JsP2PKSpendingConditions;use crate::nuts::nut14::JsHTLCSpendingConditions;use crate::nuts::{JsCurrencyUnit, JsMintInfo, JsProof};use crate::types::melt_quote::JsMeltQuote;use crate::types::{JsAmount, JsMelted, JsMintQuote};#[wasm_bindgen(js_name = Wallet)]pub struct JsWallet {    inner: Wallet,}impl Deref for JsWallet {    type Target = Wallet;    fn deref(&self) -> &Self::Target {        &self.inner    }}impl From<Wallet> for JsWallet {    fn from(inner: Wallet) -> JsWallet {        JsWallet { inner }    }}#[wasm_bindgen(js_class = Wallet)]impl JsWallet {    #[wasm_bindgen(constructor)]    pub async fn new(seed: Vec<u8>) -> Self {        let db = RexieWalletDatabase::new().await.unwrap();        Wallet::new(Arc::new(db), &seed).into()    }    #[wasm_bindgen(js_name = unitBalance)]    pub async fn unit_balance(&self, unit: JsCurrencyUnit) -> Result<JsAmount> {        Ok(self            .inner            .unit_balance(unit.into())            .await            .map_err(into_err)?            .into())    }    #[wasm_bindgen(js_name = pendingUnitBalance)]    pub async fn pending_unit_balance(&self, unit: JsCurrencyUnit) -> Result<JsAmount> {        Ok(self            .inner            .pending_unit_balance(unit.into())            .await            .map_err(into_err)?            .into())    }    #[wasm_bindgen(js_name = totalBalance)]    pub async fn total_balance(&self) -> Result<JsValue> {        Ok(serde_wasm_bindgen::to_value(            &self.inner.total_balance().await.map_err(into_err)?,        )?)    }    #[wasm_bindgen(js_name = totalPendingBalance)]    pub async fn total_pending_balance(&self) -> Result<JsValue> {        Ok(serde_wasm_bindgen::to_value(            &self.inner.total_pending_balance().await.map_err(into_err)?,        )?)    }    #[wasm_bindgen(js_name = checkAllPendingProofs)]    pub async fn check_all_pending_proofs(&self, mint_url: Option<String>) -> Result<JsAmount> {        let mint_url = match mint_url {            Some(url) => Some(UncheckedUrl::from_str(&url).map_err(into_err)?),            None => None,        };        Ok(self            .inner            .check_all_pending_proofs(mint_url)            .await            .map_err(into_err)?            .into())    }    #[wasm_bindgen(js_name = mintBalances)]    pub async fn mint_balances(&self) -> Result<JsValue> {        let mint_balances = self.inner.mint_balances().await.map_err(into_err)?;        Ok(serde_wasm_bindgen::to_value(&mint_balances)?)    }    #[wasm_bindgen(js_name = addMint)]    pub async fn add_mint(&self, mint_url: String) -> Result<Option<JsMintInfo>> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        Ok(self            .inner            .add_mint(mint_url)            .await            .map_err(into_err)?            .map(|i| i.into()))    }    #[wasm_bindgen(js_name = refreshMint)]    pub async fn refresh_mint_keys(&self, mint_url: String) -> Result<()> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        self.inner            .refresh_mint_keys(&mint_url)            .await            .map_err(into_err)?;        Ok(())    }    #[wasm_bindgen(js_name = mintQuote)]    pub async fn mint_quote(        &mut self,        mint_url: String,        amount: u64,        unit: JsCurrencyUnit,    ) -> Result<JsMintQuote> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let quote = self            .inner            .mint_quote(mint_url, amount.into(), unit.into())            .await            .map_err(into_err)?;        Ok(quote.into())    }    #[wasm_bindgen(js_name = mintQuoteStatus)]    pub async fn mint_quote_status(        &self,        mint_url: String,        quote_id: String,    ) -> Result<JsMintQuoteBolt11Response> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let quote = self            .inner            .mint_quote_status(mint_url, "e_id)            .await            .map_err(into_err)?;        Ok(quote.into())    }    #[wasm_bindgen(js_name = checkAllMintQuotes)]    pub async fn check_all_mint_quotes(&self) -> Result<JsAmount> {        let amount = self.inner.check_all_mint_quotes().await.map_err(into_err)?;        Ok(amount.into())    }    #[wasm_bindgen(js_name = mint)]    pub async fn mint(        &mut self,        mint_url: String,        quote_id: String,        split_target_amount: Option<JsAmount>,    ) -> Result<JsAmount> {        let target = split_target_amount            .map(|a| SplitTarget::Value(*a.deref()))            .unwrap_or_default();        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        Ok(self            .inner            .mint(mint_url, "e_id, target)            .await            .map_err(into_err)?            .into())    }    #[wasm_bindgen(js_name = meltQuote)]    pub async fn melt_quote(        &mut self,        mint_url: String,        unit: JsCurrencyUnit,        request: String,    ) -> Result<JsMeltQuote> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let melt_quote = self            .inner            .melt_quote(mint_url, unit.into(), request)            .await            .map_err(into_err)?;        Ok(melt_quote.into())    }    #[wasm_bindgen(js_name = meltQuoteStatus)]    pub async fn melt_quote_status(        &self,        mint_url: String,        quote_id: String,    ) -> Result<JsMeltQuoteBolt11Response> {        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let quote = self            .inner            .melt_quote_status(mint_url, "e_id)            .await            .map_err(into_err)?;        Ok(quote.into())    }    #[wasm_bindgen(js_name = melt)]    pub async fn melt(        &mut self,        mint_url: String,        quote_id: String,        split_target_amount: Option<JsAmount>,    ) -> Result<JsMelted> {        let target = split_target_amount            .map(|a| SplitTarget::Value(*a.deref()))            .unwrap_or_default();        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let melted = self            .inner            .melt(&mint_url, "e_id, target)            .await            .map_err(into_err)?;        Ok(melted.into())    }    #[wasm_bindgen(js_name = receive)]    pub async fn receive(        &mut self,        encoded_token: String,        signing_keys: JsValue,        preimages: JsValue,    ) -> Result<JsAmount> {        let signing_keys: Option<Vec<SecretKey>> = serde_wasm_bindgen::from_value(signing_keys)?;        let preimages: Option<Vec<String>> = serde_wasm_bindgen::from_value(preimages)?;        Ok(self            .inner            .receive(                &encoded_token,                &SplitTarget::default(),                signing_keys,                preimages,            )            .await            .map_err(into_err)?            .into())    }    #[allow(clippy::too_many_arguments)]    #[wasm_bindgen(js_name = send)]    pub async fn send(        &mut self,        mint_url: String,        unit: JsCurrencyUnit,        memo: Option<String>,        amount: u64,        p2pk_condition: Option<JsP2PKSpendingConditions>,        htlc_condition: Option<JsHTLCSpendingConditions>,        split_target_amount: Option<JsAmount>,    ) -> Result<String> {        let conditions = match (p2pk_condition, htlc_condition) {            (Some(_), Some(_)) => {                return Err(JsValue::from_str(                    "Cannot define both p2pk and htlc conditions",                ));            }            (None, Some(htlc_condition)) => Some(htlc_condition.deref().clone()),            (Some(p2pk_condition), None) => Some(p2pk_condition.deref().clone()),            (None, None) => None,        };        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let target = split_target_amount            .map(|a| SplitTarget::Value(*a.deref()))            .unwrap_or_default();        self.inner            .send(                &mint_url,                unit.into(),                memo,                Amount::from(amount),                &target,                conditions,            )            .await            .map_err(into_err)    }    #[allow(clippy::too_many_arguments)]    #[wasm_bindgen(js_name = swap)]    pub async fn swap(        &mut self,        mint_url: String,        unit: JsCurrencyUnit,        amount: u64,        input_proofs: Vec<JsProof>,        p2pk_condition: Option<JsP2PKSpendingConditions>,        htlc_condition: Option<JsHTLCSpendingConditions>,        split_target_amount: Option<JsAmount>,    ) -> Result<JsValue> {        let conditions = match (p2pk_condition, htlc_condition) {            (Some(_), Some(_)) => {                return Err(JsValue::from_str(                    "Cannot define both p2pk and htlc conditions",                ));            }            (None, Some(htlc_condition)) => Some(htlc_condition.deref().clone()),            (Some(p2pk_condition), None) => Some(p2pk_condition.deref().clone()),            (None, None) => None,        };        let mint_url = UncheckedUrl::from_str(&mint_url).map_err(into_err)?;        let proofs: Proofs = input_proofs.iter().map(|p| p.deref()).cloned().collect();        let target = split_target_amount            .map(|a| SplitTarget::Value(*a.deref()))            .unwrap_or_default();        let post_swap_proofs = self            .inner            .swap(                &mint_url,                &unit.into(),                Some(Amount::from(amount)),                &target,                proofs,                conditions,            )            .await            .map_err(into_err)?;        Ok(serde_wasm_bindgen::to_value(&post_swap_proofs)?)    }}
 |