diff --git a/.helix/languages.toml b/.helix/languages.toml index a79ac06f..a7c3f804 100644 --- a/.helix/languages.toml +++ b/.helix/languages.toml @@ -1,4 +1,4 @@ [[language]] name = "rust" -config = { cargo = { features = [ "blocking", "wallet" ] } } +config = { cargo = { features = [ "blocking", "wallet", "mint" ] } } diff --git a/bindings/cashu-ffi/Cargo.toml b/bindings/cashu-ffi/Cargo.toml index 6d2c1c3b..94d5ca34 100644 --- a/bindings/cashu-ffi/Cargo.toml +++ b/bindings/cashu-ffi/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["lib", "cdylib", "staticlib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cashu = { path = "../../crates/cashu", featues = ["wallet", "mint"] } +cashu = { path = "../../crates/cashu", features = ["wallet", "mint"] } url = { workspace = true } uniffi = { workspace = true } diff --git a/bindings/cashu-ffi/justfile b/bindings/cashu-ffi/justfile index 0a1db92e..f441304d 100644 --- a/bindings/cashu-ffi/justfile +++ b/bindings/cashu-ffi/justfile @@ -6,56 +6,6 @@ init: cargo install cbindgen cargo install cargo-ndk - -kotlin: - $(JUST) ffi-kotlin-clean - $(JUST) ffi-kotlin-generate - -ffi-kotlin-clean: - find ./ffi/kotlin/jniLibs -name libcashu_sdk_ffi.so -type f -delete - -ffi-kotlin-generate: - cargo run -p uniffi-bindgen generate src/cashu.udl --language kotlin --no-format -o ffi/kotlin - -android: aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android - -aarch64-linux-android: - cargo ndk -t aarch64-linux-android -o ffi/kotlin/jniLibs build --release - -armv7-linux-androideabi: - $(JUST) ffi-ndk-build TARGET=armv7-linux-androideabi - -i686-linux-android: - $(JUST) ffi-ndk-build TARGET=i686-linux-android - -x86_64-linux-android: - $(JUST) ffi-ndk-build TARGET=x86_64-linux-android - -ffi-ndk-build: - cargo ndk -t $(TARGET) -o ffi/kotlin/jniLibs build --release - -bindings-android: - $(JUST) bindings-android-clean - $(JUST) bindings-android-copy - cd bindings-android && ./gradlew assemble - $(JUST) bindings-android-package - -bindings-android-clean: - rm -rf bindings-android/lib/src/main/jniLibs - rm -rf bindings-android/lib/src/main/kotlin - -bindings-android-copy: - cp -r ffi/kotlin/jniLibs bindings-android/lib/src/main - cp -r ffi/kotlin/cashu bindings-android/lib/src/main/kotlin/ - -bindings-android-package: - mkdir -p ffi/android - cp bindings-android/lib/build/outputs/aar/lib-release.aar ffi/android - -publish-android: - cd bindings-android && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository - - python: rm -rf dist pip install -r bindings-python/requirements.txt diff --git a/bindings/cashu-ffi/src/nuts/nut00/blinded_messages.rs b/bindings/cashu-ffi/src/nuts/nut00/blinded_messages.rs index 271db5b5..d6877323 100644 --- a/bindings/cashu-ffi/src/nuts/nut00/blinded_messages.rs +++ b/bindings/cashu-ffi/src/nuts/nut00/blinded_messages.rs @@ -59,3 +59,15 @@ impl BlindedMessages { .collect() } } + +impl From for BlindedMessages { + fn from(inner: cashu::nuts::nut00::wallet::BlindedMessages) -> BlindedMessages { + BlindedMessages { inner } + } +} + +impl From for cashu::nuts::nut00::wallet::BlindedMessages { + fn from(blinded_messages: BlindedMessages) -> cashu::nuts::nut00::wallet::BlindedMessages { + blinded_messages.inner + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut00/mint_proofs.rs b/bindings/cashu-ffi/src/nuts/nut00/mint_proofs.rs index 49a41237..17ce2ced 100644 --- a/bindings/cashu-ffi/src/nuts/nut00/mint_proofs.rs +++ b/bindings/cashu-ffi/src/nuts/nut00/mint_proofs.rs @@ -32,14 +32,12 @@ impl MintProofs { } pub fn proofs(&self) -> Vec> { - let proofs = self - .inner + self.inner .proofs .clone() .into_iter() .map(|p| Arc::new(p.into())) - .collect(); - proofs + .collect() } } diff --git a/bindings/cashu-ffi/src/nuts/nut00/token.rs b/bindings/cashu-ffi/src/nuts/nut00/token.rs index 489825f7..5a712169 100644 --- a/bindings/cashu-ffi/src/nuts/nut00/token.rs +++ b/bindings/cashu-ffi/src/nuts/nut00/token.rs @@ -8,7 +8,7 @@ use crate::MintProofs; use crate::Proof; pub struct Token { - token: TokenSdk, + inner: TokenSdk, } impl Token { @@ -16,12 +16,12 @@ impl Token { let mint = url::Url::from_str(&mint)?; let proofs = proofs.into_iter().map(|p| p.as_ref().into()).collect(); Ok(Self { - token: TokenSdk::new(mint, proofs, memo)?, + inner: TokenSdk::new(mint, proofs, memo)?, }) } pub fn token(&self) -> Vec> { - self.token + self.inner .token .clone() .into_iter() @@ -30,16 +30,22 @@ impl Token { } pub fn memo(&self) -> Option { - self.token.memo.clone() + self.inner.memo.clone() } pub fn from_string(token: String) -> Result { Ok(Self { - token: TokenSdk::from_str(&token)?, + inner: TokenSdk::from_str(&token)?, }) } pub fn as_string(&self) -> Result { - Ok(self.token.convert_to_string()?) + Ok(self.inner.convert_to_string()?) + } +} + +impl From for Token { + fn from(inner: cashu::nuts::nut00::wallet::Token) -> Token { + Token { inner } } } diff --git a/bindings/cashu-ffi/src/nuts/nut02/key_set.rs b/bindings/cashu-ffi/src/nuts/nut02/key_set.rs index ba2c6798..2b0afe33 100644 --- a/bindings/cashu-ffi/src/nuts/nut02/key_set.rs +++ b/bindings/cashu-ffi/src/nuts/nut02/key_set.rs @@ -53,3 +53,9 @@ impl KeySetResponse { self.inner.clone().keysets.into_iter().collect() } } + +impl From for KeySetResponse { + fn from(inner: Response) -> KeySetResponse { + KeySetResponse { inner } + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut03/mod.rs b/bindings/cashu-ffi/src/nuts/nut03/mod.rs index 963df8a4..288598a7 100644 --- a/bindings/cashu-ffi/src/nuts/nut03/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut03/mod.rs @@ -25,3 +25,11 @@ impl RequestMintResponse { self.inner.hash.to_string() } } + +impl From for RequestMintResponse { + fn from(mint_response: cashu::nuts::nut03::RequestMintResponse) -> RequestMintResponse { + RequestMintResponse { + inner: mint_response, + } + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut04/mod.rs b/bindings/cashu-ffi/src/nuts/nut04/mod.rs index b49119a5..0e0b3e96 100644 --- a/bindings/cashu-ffi/src/nuts/nut04/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut04/mod.rs @@ -56,3 +56,9 @@ impl PostMintResponse { .collect() } } + +impl From for PostMintResponse { + fn from(inner: cashu::nuts::nut04::PostMintResponse) -> PostMintResponse { + PostMintResponse { inner } + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut05/mod.rs b/bindings/cashu-ffi/src/nuts/nut05/mod.rs index 8329b091..8f1b88d0 100644 --- a/bindings/cashu-ffi/src/nuts/nut05/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut05/mod.rs @@ -46,6 +46,18 @@ impl CheckFeesResponse { } } +impl From for CheckFeesResponse { + fn from(inner: cashu::nuts::nut05::CheckFeesResponse) -> CheckFeesResponse { + Self { inner } + } +} + +impl From for cashu::nuts::nut05::CheckFeesResponse { + fn from(res: CheckFeesResponse) -> cashu::nuts::nut05::CheckFeesResponse { + res.inner + } +} + pub struct MeltRequest { inner: MeltRequestSdk, } diff --git a/bindings/cashu-ffi/src/nuts/nut06/mod.rs b/bindings/cashu-ffi/src/nuts/nut06/mod.rs index d3283e40..4b1c1db0 100644 --- a/bindings/cashu-ffi/src/nuts/nut06/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut06/mod.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{ops::Deref, sync::Arc}; use cashu::nuts::nut06::{SplitRequest as SplitRequestSdk, SplitResponse as SplitResponseSdk}; @@ -8,6 +8,13 @@ pub struct SplitRequest { inner: SplitRequestSdk, } +impl Deref for SplitRequest { + type Target = SplitRequestSdk; + fn deref(&self) -> &Self::Target { + &self.inner + } +} + impl SplitRequest { pub fn new(proofs: Vec>, outputs: Vec>) -> Self { let proofs = proofs.into_iter().map(|p| p.as_ref().into()).collect(); @@ -79,3 +86,9 @@ impl SplitResponse { self.inner.promises_amount().map(|a| Arc::new(a.into())) } } + +impl From for SplitResponse { + fn from(inner: cashu::nuts::nut06::SplitResponse) -> SplitResponse { + SplitResponse { inner } + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut07/mod.rs b/bindings/cashu-ffi/src/nuts/nut07/mod.rs index eb6595c1..41db6678 100644 --- a/bindings/cashu-ffi/src/nuts/nut07/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut07/mod.rs @@ -49,3 +49,9 @@ impl CheckSpendableResponse { self.inner.pending.clone() } } + +impl From for CheckSpendableResponse { + fn from(inner: cashu::nuts::nut07::CheckSpendableResponse) -> CheckSpendableResponse { + CheckSpendableResponse { inner } + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut08/mod.rs b/bindings/cashu-ffi/src/nuts/nut08/mod.rs index 3174dd20..7e2bb052 100644 --- a/bindings/cashu-ffi/src/nuts/nut08/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut08/mod.rs @@ -85,3 +85,15 @@ impl MeltResponse { .map(|change| change.into_iter().map(|bs| Arc::new(bs.into())).collect()) } } + +impl From for MeltResponse { + fn from(inner: cashu::nuts::nut08::MeltResponse) -> MeltResponse { + MeltResponse { inner } + } +} + +impl From for cashu::nuts::nut08::MeltResponse { + fn from(res: MeltResponse) -> cashu::nuts::nut08::MeltResponse { + res.inner + } +} diff --git a/bindings/cashu-ffi/src/nuts/nut09/mod.rs b/bindings/cashu-ffi/src/nuts/nut09/mod.rs index fe377aef..7aec20e9 100644 --- a/bindings/cashu-ffi/src/nuts/nut09/mod.rs +++ b/bindings/cashu-ffi/src/nuts/nut09/mod.rs @@ -74,3 +74,9 @@ impl MintInfo { } } } + +impl From for MintInfo { + fn from(inner: cashu::nuts::nut09::MintInfo) -> MintInfo { + MintInfo { inner } + } +} diff --git a/bindings/cashu-sdk-ffi/bindings-python/.gitignore b/bindings/cashu-sdk-ffi/bindings-python/.gitignore index f186bda5..729b25c7 100644 --- a/bindings/cashu-sdk-ffi/bindings-python/.gitignore +++ b/bindings/cashu-sdk-ffi/bindings-python/.gitignore @@ -13,5 +13,4 @@ src/cashu-sdk/*.so *.whl build/ -testing-setup-py-simple-example.py diff --git a/bindings/cashu-sdk-ffi/bindings-python/examples/test.py b/bindings/cashu-sdk-ffi/bindings-python/examples/test.py new file mode 100644 index 00000000..c6e1ca9a --- /dev/null +++ b/bindings/cashu-sdk-ffi/bindings-python/examples/test.py @@ -0,0 +1,3 @@ +import cashu_sdk; + +help(cashu_sdk) \ No newline at end of file diff --git a/bindings/cashu-sdk-ffi/src/cashu_sdk.udl b/bindings/cashu-sdk-ffi/src/cashu_sdk.udl index 8a429b0f..ba78f465 100644 --- a/bindings/cashu-sdk-ffi/src/cashu_sdk.udl +++ b/bindings/cashu-sdk-ffi/src/cashu_sdk.udl @@ -7,6 +7,14 @@ interface CashuError { Generic(string err); }; + +interface Bolt11Invoice { + [Throws=CashuError] + constructor(string bolt11); + string as_string(); + Amount? amount(); +}; + interface Amount { u64 to_sat(); u64 to_msat(); @@ -216,4 +224,73 @@ enum InvoiceStatus { "Paid", "Expired", "InFlight" +}; + +// Cashu Sdk + + +[Error] +interface CashuSdkError { + Generic(string err); +}; + +interface SendProofs { + constructor(sequence change_proofs, sequence send_proofs); + sequence send_proofs(); + sequence change_proofs(); +}; + +interface Melted { + constructor(boolean paid, string? preimage, sequence? change); + string? preimage(); + boolean paid(); + 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); + // TODO: ProofStatus type + // [Throws=CashuSdkError] + // ProofsStatus check_proofs_spent(sequence proofs); + [Throws=CashuSdkError] + RequestMintResponse request_mint(Amount amount); + [Throws=CashuSdkError] + Token mint_token(Amount amount, string hash); + [Throws=CashuSdkError] + sequence mint(Amount amount, string hash); + [Throws=CashuSdkError] + Amount check_fee(Bolt11Invoice invoice); + [Throws=CashuSdkError] + sequence receive(string encoded_token); + [Throws=CashuSdkError] + sequence process_split_response(BlindedMessages blinded_messages, sequence promises); + [Throws=CashuSdkError] + SendProofs send(Amount amount, sequence proofs); + [Throws=CashuSdkError] + Melted melt(Bolt11Invoice invoice, sequence proofs, Amount fee_reserve); + [Throws=CashuSdkError] + string proof_to_token(sequence proof, string? memo); }; \ No newline at end of file diff --git a/bindings/cashu-sdk-ffi/src/client.rs b/bindings/cashu-sdk-ffi/src/client.rs new file mode 100644 index 00000000..c5a18ccd --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/client.rs @@ -0,0 +1,105 @@ +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/error.rs b/bindings/cashu-sdk-ffi/src/error.rs new file mode 100644 index 00000000..bed41221 --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/error.rs @@ -0,0 +1,32 @@ +use std::fmt; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum CashuSdkError { + Generic { err: String }, +} + +impl fmt::Display for CashuSdkError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Generic { err } => write!(f, "{err}"), + } + } +} + +impl From for CashuSdkError { + fn from(err: cashu_sdk::client::Error) -> CashuSdkError { + Self::Generic { + err: err.to_string(), + } + } +} + +impl From for CashuSdkError { + fn from(err: cashu_sdk::wallet::Error) -> CashuSdkError { + Self::Generic { + err: err.to_string(), + } + } +} diff --git a/bindings/cashu-sdk-ffi/src/lib.rs b/bindings/cashu-sdk-ffi/src/lib.rs index 745e9fe5..a7a8b64e 100644 --- a/bindings/cashu-sdk-ffi/src/lib.rs +++ b/bindings/cashu-sdk-ffi/src/lib.rs @@ -1,12 +1,23 @@ +mod client; +mod error; +mod types; +mod wallet; + mod ffi { pub use cashu_ffi::{ - Amount, BlindedMessage, BlindedMessages, BlindedSignature, CashuError, CheckFeesRequest, - CheckFeesResponse, CheckSpendableRequest, CheckSpendableResponse, InvoiceStatus, KeyPair, - KeySet, KeySetResponse, Keys, MeltRequest, MeltResponse, MintInfo, MintProof, MintProofs, - MintRequest, MintVersion, Nut05MeltRequest, Nut05MeltResponse, PostMintResponse, Proof, - PublicKey, RequestMintResponse, SecretKey, SplitRequest, SplitResponse, Token, + Amount, BlindedMessage, BlindedMessages, BlindedSignature, Bolt11Invoice, CashuError, + CheckFeesRequest, CheckFeesResponse, CheckSpendableRequest, CheckSpendableResponse, + InvoiceStatus, KeyPair, KeySet, KeySetResponse, Keys, MeltRequest, MeltResponse, MintInfo, + MintProof, MintProofs, MintRequest, MintVersion, Nut05MeltRequest, Nut05MeltResponse, + PostMintResponse, Proof, PublicKey, RequestMintResponse, SecretKey, SplitRequest, + SplitResponse, Token, }; + pub use crate::client::Client; + pub use crate::error::CashuSdkError; + pub use crate::types::{Melted, SendProofs}; + pub use crate::wallet::Wallet; + // UDL uniffi::include_scaffolding!("cashu_sdk"); } diff --git a/bindings/cashu-sdk-ffi/src/types/melted.rs b/bindings/cashu-sdk-ffi/src/types/melted.rs new file mode 100644 index 00000000..9bea4307 --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/types/melted.rs @@ -0,0 +1,42 @@ +use std::{ops::Deref, sync::Arc}; + +use cashu_sdk::types::Melted as MeltedSdk; + +use cashu_ffi::Proof; + +pub struct Melted { + inner: MeltedSdk, +} + +impl Melted { + pub fn new(paid: bool, preimage: Option, change: Option>>) -> Self { + Self { + inner: MeltedSdk { + paid, + preimage, + change: change.map(|c| c.iter().map(|p| p.as_ref().deref().clone()).collect()), + }, + } + } + + pub fn preimage(&self) -> Option { + self.inner.preimage.clone() + } + + pub fn paid(&self) -> bool { + self.inner.paid + } + + pub fn change(&self) -> Option>> { + self.inner + .change + .clone() + .map(|c| c.into_iter().map(|p| Arc::new(p.into())).collect()) + } +} + +impl From for Melted { + fn from(inner: cashu_sdk::types::Melted) -> Melted { + Melted { inner } + } +} diff --git a/bindings/cashu-sdk-ffi/src/types/mod.rs b/bindings/cashu-sdk-ffi/src/types/mod.rs new file mode 100644 index 00000000..cd6460fe --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/types/mod.rs @@ -0,0 +1,5 @@ +pub mod melted; +pub mod send_proofs; + +pub use melted::Melted; +pub use send_proofs::SendProofs; diff --git a/bindings/cashu-sdk-ffi/src/types/send_proofs.rs b/bindings/cashu-sdk-ffi/src/types/send_proofs.rs new file mode 100644 index 00000000..ac50a045 --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/types/send_proofs.rs @@ -0,0 +1,50 @@ +use std::{ops::Deref, sync::Arc}; + +use cashu_sdk::types::SendProofs as SendProofSdk; + +use cashu_ffi::Proof; + +pub struct SendProofs { + inner: SendProofSdk, +} + +impl SendProofs { + pub fn new(change_proofs: Vec>, send_proofs: Vec>) -> Self { + Self { + inner: SendProofSdk { + change_proofs: change_proofs + .iter() + .map(|p| p.as_ref().deref().clone()) + .collect(), + send_proofs: send_proofs + .iter() + .map(|p| p.as_ref().deref().clone()) + .collect(), + }, + } + } + + pub fn send_proofs(&self) -> Vec> { + self.inner + .send_proofs + .clone() + .into_iter() + .map(|p| Arc::new(p.into())) + .collect() + } + + pub fn change_proofs(&self) -> Vec> { + self.inner + .change_proofs + .clone() + .into_iter() + .map(|p| Arc::new(p.into())) + .collect() + } +} + +impl From for SendProofs { + fn from(inner: cashu_sdk::types::SendProofs) -> SendProofs { + SendProofs { inner } + } +} diff --git a/bindings/cashu-sdk-ffi/src/wallet.rs b/bindings/cashu-sdk-ffi/src/wallet.rs new file mode 100644 index 00000000..49f63ca2 --- /dev/null +++ b/bindings/cashu-sdk-ffi/src/wallet.rs @@ -0,0 +1,127 @@ +use std::ops::Deref; +use std::sync::Arc; + +use cashu_ffi::{ + BlindedMessages, BlindedSignature, Bolt11Invoice, Proof, RequestMintResponse, Token, +}; +use cashu_sdk::types::ProofsStatus; +use cashu_sdk::wallet::Wallet as WalletSdk; + +use crate::{ + client::Client, + error::Result, + types::{Melted, SendProofs}, + Amount, Keys, MintProof, +}; + +pub struct Wallet { + inner: WalletSdk, +} + +impl Wallet { + pub fn new(client: Arc, mint_keys: Arc) -> Self { + Self { + inner: WalletSdk::new( + client.as_ref().deref().clone(), + 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(), + )?)) + } + + pub fn request_mint(&self, amount: Arc) -> Result> { + Ok(Arc::new( + self.inner.request_mint(*amount.as_ref().deref())?.into(), + )) + } + + pub fn mint_token(&self, amount: Arc, hash: String) -> Result> { + Ok(Arc::new( + self.inner + .mint_token(*amount.as_ref().deref(), &hash)? + .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()) + } + + pub fn check_fee(&self, invoice: Arc) -> Result> { + Ok(Arc::new( + self.inner + .check_fee(invoice.as_ref().deref().clone())? + .into(), + )) + } + + pub fn receive(&self, encoded_token: String) -> Result>> { + Ok(self + .inner + .receive(&encoded_token)? + .into_iter() + .map(|p| Arc::new(p.into())) + .collect()) + } + + pub fn process_split_response( + &self, + blinded_messages: Arc, + promises: Vec>, + ) -> Result>> { + Ok(self + .inner + .process_split_response( + blinded_messages.as_ref().deref().clone(), + promises.iter().map(|p| p.as_ref().deref().into()).collect(), + )? + .into_iter() + .map(|p| Arc::new(p.into())) + .collect()) + } + + pub fn send(&self, amount: Arc, proofs: Vec>) -> Result> { + Ok(Arc::new( + self.inner + .send( + *amount.as_ref().deref(), + proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), + )? + .into(), + )) + } + + pub fn melt( + &self, + invoice: Arc, + proofs: Vec>, + fee_reserve: Arc, + ) -> Result> { + Ok(Arc::new( + self.inner + .melt( + invoice.as_ref().deref().clone(), + proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), + *fee_reserve.as_ref().deref(), + )? + .into(), + )) + } + + pub fn proof_to_token(&self, proofs: Vec>, memo: Option) -> Result { + Ok(self.inner.proofs_to_token( + proofs.iter().map(|p| p.as_ref().deref().clone()).collect(), + memo, + )?) + } +} diff --git a/crates/cashu-sdk/src/client/blocking.rs b/crates/cashu-sdk/src/client/blocking.rs index 12dee6ad..072b40bb 100644 --- a/crates/cashu-sdk/src/client/blocking.rs +++ b/crates/cashu-sdk/src/client/blocking.rs @@ -44,10 +44,10 @@ impl Client { pub fn mint( &self, - blinded_mssages: BlindedMessages, + blinded_messages: BlindedMessages, hash: &str, ) -> Result { - RUNTIME.block_on(async { self.client.mint(blinded_mssages, hash).await }) + RUNTIME.block_on(async { self.client.mint(blinded_messages, hash).await }) } pub fn check_fees(&self, invoice: Bolt11Invoice) -> Result { diff --git a/crates/cashu/src/nuts/nut01.rs b/crates/cashu/src/nuts/nut01.rs index 7741aa37..4eef837b 100644 --- a/crates/cashu/src/nuts/nut01.rs +++ b/crates/cashu/src/nuts/nut01.rs @@ -88,7 +88,7 @@ impl Keys { self.0.get(&amount.to_sat()).cloned() } - /// As seralized hashmap + /// As serialized hashmap pub fn as_hashmap(&self) -> HashMap { self.0 .iter()