diff --git a/bindings/cashu-sdk-ffi/Cargo.toml b/bindings/cashu-sdk-ffi/Cargo.toml index e7b11cb4..f065321e 100644 --- a/bindings/cashu-sdk-ffi/Cargo.toml +++ b/bindings/cashu-sdk-ffi/Cargo.toml @@ -12,10 +12,18 @@ crate-type = ["cdylib", "staticlib"] [dependencies] cashu-ffi = { path = "../cashu-ffi" } -cashu-sdk = { path = "../../crates/cashu-sdk", default-features = false, features = ["wallet", "mint"] } +cashu-sdk = { path = "../../crates/cashu-sdk", default-features = false, features = ["wallet", "mint", "all-nuts"] } tracing = { workspace = true } tracing-subscriber = { workspace = true } uniffi = { workspace = true } +futures = { version= "0.3.29", feature = "executor" } +once_cell = { version = "1.17" } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +tokio = { workspace = true, features = ["rt-multi-thread", "time", "macros", "sync"] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +tokio = { workspace = true, features = ["rt", "macros", "sync", "time"] } [build-dependencies] uniffi = { workspace = true, features = ["build"] } diff --git a/bindings/cashu-sdk-ffi/src/cashu_sdk.udl b/bindings/cashu-sdk-ffi/src/cashu_sdk.udl index dba4caef..6e428746 100644 --- a/bindings/cashu-sdk-ffi/src/cashu_sdk.udl +++ b/bindings/cashu-sdk-ffi/src/cashu_sdk.udl @@ -289,31 +289,7 @@ interface Melted { sequence? change(); }; -interface Client { - [Throws=CashuSdkError] - constructor(string mint_url); - [Throws=CashuSdkError] - Keys get_keys(); - [Throws=CashuSdkError] - KeySetResponse get_keysets(); - [Throws=CashuSdkError] - RequestMintResponse request_mint(Amount amount); - [Throws=CashuSdkError] - PostMintResponse mint(BlindedMessages blinded_messages, string hash); - [Throws=CashuSdkError] - CheckFeesResponse check_fees(Bolt11Invoice invoice); - [Throws=CashuSdkError] - MeltResponse melt(sequence proofs, Bolt11Invoice invoice, sequence? outputs); - [Throws=CashuSdkError] - SplitResponse split(SplitRequest split_request); - [Throws=CashuSdkError] - CheckSpendableResponse check_spendable(sequence proofs); - [Throws=CashuSdkError] - MintInfo get_info(); -}; - interface Wallet { - constructor(Client client, Keys mint_keys); // [Throws=CashuSdkError] // ProofsStatus check_proofs_spent(sequence proofs); [Throws=CashuSdkError] diff --git a/bindings/cashu-sdk-ffi/src/client.rs b/bindings/cashu-sdk-ffi/src/client.rs deleted file mode 100644 index c5a18ccd..00000000 --- a/bindings/cashu-sdk-ffi/src/client.rs +++ /dev/null @@ -1,105 +0,0 @@ -use std::ops::Deref; -use std::sync::Arc; - -use cashu_ffi::{ - BlindedMessage, BlindedMessages, Bolt11Invoice, CheckFeesResponse, CheckSpendableResponse, - KeySetResponse, MeltResponse, MintInfo, MintProof, PostMintResponse, Proof, - RequestMintResponse, SplitRequest, SplitResponse, -}; -use cashu_sdk::client::blocking::Client as ClientSdk; - -use crate::error::Result; -use crate::{Amount, Keys}; - -pub struct Client { - inner: ClientSdk, -} - -impl Deref for Client { - type Target = ClientSdk; - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl Client { - pub fn new(mint_url: String) -> Result { - Ok(Self { - inner: ClientSdk::new(&mint_url)?, - }) - } - - pub fn get_keys(&self) -> Result> { - Ok(Arc::new(self.inner.get_keys()?.into())) - } - - pub fn get_keysets(&self) -> Result> { - Ok(Arc::new(self.inner.get_keysets()?.into())) - } - - pub fn request_mint(&self, amount: Arc) -> Result> { - Ok(Arc::new( - self.inner.request_mint(*amount.as_ref().deref())?.into(), - )) - } - - pub fn mint( - &self, - blinded_messages: Arc, - hash: String, - ) -> Result> { - Ok(Arc::new( - self.inner - .mint(blinded_messages.as_ref().deref().clone(), &hash)? - .into(), - )) - } - - pub fn check_fees(&self, invoice: Arc) -> Result> { - Ok(Arc::new( - self.inner - .check_fees(invoice.as_ref().deref().clone())? - .into(), - )) - } - - pub fn melt( - &self, - proofs: Vec>, - invoice: Arc, - outputs: Option>>, - ) -> Result> { - Ok(Arc::new( - self.inner - .melt( - proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), - invoice.as_ref().deref().clone(), - outputs.map(|bs| bs.iter().map(|b| b.as_ref().deref().clone()).collect()), - )? - .into(), - )) - } - - pub fn split(&self, split_request: Arc) -> Result> { - Ok(Arc::new( - self.inner - .split(split_request.as_ref().deref().clone())? - .into(), - )) - } - - pub fn check_spendable( - &self, - proofs: Vec>, - ) -> Result> { - Ok(Arc::new( - self.inner - .check_spendable(&proofs.iter().map(|p| p.as_ref().deref().clone()).collect())? - .into(), - )) - } - - pub fn get_info(&self) -> Result> { - Ok(Arc::new(self.inner.get_info()?.into())) - } -} diff --git a/bindings/cashu-sdk-ffi/src/lib.rs b/bindings/cashu-sdk-ffi/src/lib.rs index ba5804ff..f84d2954 100644 --- a/bindings/cashu-sdk-ffi/src/lib.rs +++ b/bindings/cashu-sdk-ffi/src/lib.rs @@ -1,4 +1,3 @@ -mod client; mod error; mod mint; mod types; @@ -14,7 +13,6 @@ mod ffi { RequestMintResponse, Secret, SecretKey, SplitRequest, SplitResponse, Token, }; - pub use crate::client::Client; pub use crate::error::CashuSdkError; pub use crate::mint::Mint; pub use crate::types::{Melted, ProofsStatus, SendProofs}; diff --git a/bindings/cashu-sdk-ffi/src/wallet.rs b/bindings/cashu-sdk-ffi/src/wallet.rs index dedd0772..ff7627a9 100644 --- a/bindings/cashu-sdk-ffi/src/wallet.rs +++ b/bindings/cashu-sdk-ffi/src/wallet.rs @@ -4,72 +4,77 @@ use std::sync::Arc; use cashu_ffi::{ BlindedMessages, BlindedSignature, Bolt11Invoice, Proof, RequestMintResponse, Token, }; +use cashu_sdk::client::minreq_client::HttpClient; use cashu_sdk::types::ProofsStatus; +use cashu_sdk::url::UncheckedUrl; use cashu_sdk::wallet::Wallet as WalletSdk; +use once_cell::sync::Lazy; +use tokio::runtime::Runtime; -use crate::client::Client; use crate::error::Result; use crate::types::{Melted, SendProofs}; use crate::{Amount, Keys, MintProof}; +static RUNTIME: Lazy = Lazy::new(|| Runtime::new().expect("Can't start Tokio runtime")); + pub struct Wallet { - inner: WalletSdk, + inner: WalletSdk, } impl Wallet { - pub fn new(client: Arc, mint_keys: Arc) -> Self { + pub fn new(mint_url: &str, mint_keys: Arc) -> Self { + let client = HttpClient {}; Self { inner: WalletSdk::new( - client.as_ref().deref().clone(), + client, + UncheckedUrl::new(mint_url), mint_keys.as_ref().deref().clone(), ), } } pub fn check_proofs_spent(&self, proofs: Vec>) -> Result> { - Ok(Arc::new(self.inner.check_proofs_spent( - &proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), - )?)) + let proofs = RUNTIME.block_on(async { + self.inner + .check_proofs_spent(proofs.iter().map(|p| p.as_ref().deref().clone()).collect()) + .await + })?; + + Ok(Arc::new(proofs)) } pub fn request_mint(&self, amount: Arc) -> Result> { - Ok(Arc::new( - self.inner.request_mint(*amount.as_ref().deref())?.into(), - )) + let mint_response = RUNTIME + .block_on(async { self.inner.request_mint(*amount.as_ref().deref()).await })? + .into(); + Ok(Arc::new(mint_response)) } pub fn mint_token(&self, amount: Arc, hash: String) -> Result> { - Ok(Arc::new( - self.inner - .mint_token(*amount.as_ref().deref(), &hash)? - .into(), - )) + let token = RUNTIME + .block_on(async { self.inner.mint_token(*amount.as_ref().deref(), &hash).await })?; + + Ok(Arc::new(token.into())) } pub fn mint(&self, amount: Arc, hash: String) -> Result>> { - Ok(self - .inner - .mint(*amount.as_ref().deref(), &hash)? - .into_iter() - .map(|p| Arc::new(p.into())) - .collect()) + let proofs = + RUNTIME.block_on(async { self.inner.mint(*amount.as_ref().deref(), &hash).await })?; + + Ok(proofs.into_iter().map(|p| Arc::new(p.into())).collect()) } pub fn check_fee(&self, invoice: Arc) -> Result> { - Ok(Arc::new( - self.inner - .check_fee(invoice.as_ref().deref().clone())? - .into(), - )) + let amount = RUNTIME + .block_on(async { self.inner.check_fee(invoice.as_ref().deref().clone()).await })?; + + Ok(Arc::new(amount.into())) } pub fn receive(&self, encoded_token: String) -> Result>> { - Ok(self - .inner - .receive(&encoded_token)? - .into_iter() - .map(|p| Arc::new(p.into())) - .collect()) + let proofs = RUNTIME.block_on(async { self.inner.receive(&encoded_token).await })?; + + Ok(proofs.into_iter().map(|p| Arc::new(p.into())).collect()) } pub fn process_split_response( @@ -81,7 +86,7 @@ impl Wallet { .inner .process_split_response( blinded_messages.as_ref().deref().clone(), - promises.iter().map(|p| p.as_ref().deref().into()).collect(), + promises.iter().map(|p| p.as_ref().into()).collect(), )? .into_iter() .map(|p| Arc::new(p.into())) @@ -89,14 +94,16 @@ impl Wallet { } pub fn send(&self, amount: Arc, proofs: Vec>) -> Result> { - Ok(Arc::new( + let send_proofs = RUNTIME.block_on(async { self.inner .send( *amount.as_ref().deref(), proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), - )? - .into(), - )) + ) + .await + })?; + + Ok(Arc::new(send_proofs.into())) } pub fn melt( @@ -105,15 +112,17 @@ impl Wallet { proofs: Vec>, fee_reserve: Arc, ) -> Result> { - Ok(Arc::new( + let melted = RUNTIME.block_on(async { self.inner .melt( invoice.as_ref().deref().clone(), proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), *fee_reserve.as_ref().deref(), - )? - .into(), - )) + ) + .await + })?; + + Ok(Arc::new(melted.into())) } pub fn proof_to_token(&self, proofs: Vec>, memo: Option) -> Result { diff --git a/crates/cashu-sdk/Cargo.toml b/crates/cashu-sdk/Cargo.toml index 60830823..44ccb7a0 100644 --- a/crates/cashu-sdk/Cargo.toml +++ b/crates/cashu-sdk/Cargo.toml @@ -13,6 +13,7 @@ license.workspace = true default = ["mint", "wallet"] mint = ["cashu/mint"] wallet = ["cashu/wallet", "dep:minreq", "dep:once_cell"] +all-nuts = ["nut07", "nut09"] nut07 = ["cashu/nut07"] # nut08 = ["cashu/nut08"] nut09 = ["cashu/nut09"]