From 05b8ecf07d2a28f33c8ec6242b42fa32c44193ac Mon Sep 17 00:00:00 2001 From: vnprc Date: Fri, 30 Aug 2024 17:24:26 -0400 Subject: [PATCH 1/6] feat: refactor generate premint secrets into a separate function This change is intended to enable devs who want to provide their own network transport to get blinded secrets without making a network call. The nix flake changes were implemented by the code formatter. --- crates/cdk/src/wallet/mod.rs | 79 +++++++++++++++++++++++++++++------- flake.nix | 6 ++- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index 4548c6c6..36a90e9f 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -564,6 +564,62 @@ impl Wallet { Ok(total_amount) } + /// Generates blinded secrets to send to the mint for signing. This function + /// is appropriate if the caller is providing their own network + /// transport. Otherwise use `mint`, which makes a network request to + /// the mint. + /// + /// # Parameters + /// + /// - `&self`: A reference to the current instance + /// - `active_keyset_id`: The ID of the active keyset + /// - `quote_info_amount`: The amount to be minted + /// - `amount_split_target`: Strategy for splitting amount into discrete + /// tokens + /// - `spending_conditions`: Optional spending conditions to apply to the + /// minted tokens + /// - `count`: How many tokens were previously generated from this keyset + + /// 1 + /// - `xpriv`: The extended private key used for generating secrets + /// + /// # Returns + /// + /// A `Result` containing `PreMintSecrets` if successful, or an `Error` + /// otherwise. + /// + /// # Errors + /// + /// This function will return an error if the creation of `PreMintSecrets` + /// fails. + /// + /// ``` + pub fn generate_premint_secrets( + &self, + active_keyset_id: Id, + quote_info_amount: Amount, + amount_split_target: &SplitTarget, + spending_conditions: Option<&SpendingConditions>, + count: u32, + xpriv: ExtendedPrivKey, + ) -> Result { + // Move the match logic into this function. + match spending_conditions { + Some(spending_conditions) => Ok(PreMintSecrets::with_conditions( + active_keyset_id, + quote_info_amount, + amount_split_target, + spending_conditions, + )?), + None => Ok(PreMintSecrets::from_xpriv( + active_keyset_id, + count, + xpriv, + quote_info_amount, + amount_split_target, + )?), + } + } + /// Mint /// # Synopsis /// ```rust @@ -632,21 +688,14 @@ impl Wallet { let count = count.map_or(0, |c| c + 1); - let premint_secrets = match &spending_conditions { - Some(spending_conditions) => PreMintSecrets::with_conditions( - active_keyset_id, - quote_info.amount, - &amount_split_target, - spending_conditions, - )?, - None => PreMintSecrets::from_xpriv( - active_keyset_id, - count, - self.xpriv, - quote_info.amount, - &amount_split_target, - )?, - }; + let premint_secrets = self.generate_premint_secrets( + active_keyset_id, + quote_info.amount, + &amount_split_target, + spending_conditions.as_ref(), + count, + self.xpriv, + )?; let mint_res = self .client diff --git a/flake.nix b/flake.nix index ece16669..6b61aa73 100644 --- a/flake.nix +++ b/flake.nix @@ -45,12 +45,14 @@ pname = "flexbox-multibuild"; src = rustSrc; }).overrideArgs commonArgs; - in rec { + in + rec { workspaceDeps = craneLib.buildWorkspaceDepsOnly { }; workspaceBuild = craneLib.buildWorkspace { cargoArtifacts = workspaceDeps; }; }); - in { + in + { devShells = flakeboxLib.mkShells { toolchain = toolchainNative; packages = [ ]; From 1c82e212505600d7135b6b18f4dbc347387d1a8d Mon Sep 17 00:00:00 2001 From: vnprc Date: Sat, 31 Aug 2024 12:54:04 -0400 Subject: [PATCH 2/6] feat: add hash currency unit --- bindings/cdk-js/src/nuts/nut00/currency_unit.rs | 3 +++ crates/cdk-strike/src/lib.rs | 3 +++ crates/cdk/src/nuts/nut00/mod.rs | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/bindings/cdk-js/src/nuts/nut00/currency_unit.rs b/bindings/cdk-js/src/nuts/nut00/currency_unit.rs index b3839591..fa5276db 100644 --- a/bindings/cdk-js/src/nuts/nut00/currency_unit.rs +++ b/bindings/cdk-js/src/nuts/nut00/currency_unit.rs @@ -9,6 +9,7 @@ pub enum JsCurrencyUnit { Msat, Usd, Eur, + Hash, } impl From for JsCurrencyUnit { @@ -18,6 +19,7 @@ impl From for JsCurrencyUnit { CurrencyUnit::Msat => JsCurrencyUnit::Msat, CurrencyUnit::Usd => JsCurrencyUnit::Usd, CurrencyUnit::Eur => JsCurrencyUnit::Eur, + CurrencyUnit::Hash => JsCurrencyUnit::Hash, } } } @@ -29,6 +31,7 @@ impl From for CurrencyUnit { JsCurrencyUnit::Msat => CurrencyUnit::Msat, JsCurrencyUnit::Usd => CurrencyUnit::Usd, JsCurrencyUnit::Eur => CurrencyUnit::Eur, + JsCurrencyUnit::Hash => CurrencyUnit::Hash, } } } diff --git a/crates/cdk-strike/src/lib.rs b/crates/cdk-strike/src/lib.rs index 42bdcc44..300cf474 100644 --- a/crates/cdk-strike/src/lib.rs +++ b/crates/cdk-strike/src/lib.rs @@ -129,6 +129,7 @@ impl MintLightning for Strike { CurrencyUnit::Msat => StrikeCurrencyUnit::BTC, CurrencyUnit::Usd => StrikeCurrencyUnit::USD, CurrencyUnit::Eur => StrikeCurrencyUnit::EUR, + CurrencyUnit::Hash => unimplemented!(), }; let payment_quote_request = PayInvoiceQuoteRequest { @@ -274,6 +275,7 @@ pub(crate) fn from_strike_amount( bail!("Could not convert to EUR"); } } + CurrencyUnit::Hash => unimplemented!(), } } @@ -301,5 +303,6 @@ where amount: euro.round() / 100.0, } } + CurrencyUnit::Hash => unimplemented!(), } } diff --git a/crates/cdk/src/nuts/nut00/mod.rs b/crates/cdk/src/nuts/nut00/mod.rs index 9ea95787..04795ef6 100644 --- a/crates/cdk/src/nuts/nut00/mod.rs +++ b/crates/cdk/src/nuts/nut00/mod.rs @@ -323,6 +323,8 @@ pub enum CurrencyUnit { Usd, /// Euro Eur, + /// Hash + Hash, } #[cfg(feature = "mint")] @@ -334,6 +336,7 @@ impl CurrencyUnit { Self::Msat => 1, Self::Usd => 2, Self::Eur => 3, + Self::Hash => 4, } } } @@ -346,6 +349,7 @@ impl FromStr for CurrencyUnit { "msat" => Ok(Self::Msat), "usd" => Ok(Self::Usd), "eur" => Ok(Self::Eur), + "hash" => Ok(Self::Hash), _ => Err(Error::UnsupportedUnit), } } @@ -358,6 +362,7 @@ impl fmt::Display for CurrencyUnit { CurrencyUnit::Msat => write!(f, "msat"), CurrencyUnit::Usd => write!(f, "usd"), CurrencyUnit::Eur => write!(f, "eur"), + CurrencyUnit::Hash => write!(f, "hash"), } } } From 5a4e3fd65fe010cc05a469421fdd7f1e07375e0b Mon Sep 17 00:00:00 2001 From: vnprc Date: Tue, 3 Sep 2024 21:58:23 -0400 Subject: [PATCH 3/6] fix: remove xpriv param from generate_premint_secrets() --- crates/cdk/src/wallet/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/cdk/src/wallet/mod.rs b/crates/cdk/src/wallet/mod.rs index 36a90e9f..932db481 100644 --- a/crates/cdk/src/wallet/mod.rs +++ b/crates/cdk/src/wallet/mod.rs @@ -580,7 +580,6 @@ impl Wallet { /// minted tokens /// - `count`: How many tokens were previously generated from this keyset + /// 1 - /// - `xpriv`: The extended private key used for generating secrets /// /// # Returns /// @@ -600,7 +599,6 @@ impl Wallet { amount_split_target: &SplitTarget, spending_conditions: Option<&SpendingConditions>, count: u32, - xpriv: ExtendedPrivKey, ) -> Result { // Move the match logic into this function. match spending_conditions { @@ -613,7 +611,7 @@ impl Wallet { None => Ok(PreMintSecrets::from_xpriv( active_keyset_id, count, - xpriv, + self.xpriv, quote_info_amount, amount_split_target, )?), @@ -694,7 +692,6 @@ impl Wallet { &amount_split_target, spending_conditions.as_ref(), count, - self.xpriv, )?; let mint_res = self From 4c2d05fdb835f1cfcedf7e5897dc5e667366c67f Mon Sep 17 00:00:00 2001 From: vnprc Date: Tue, 10 Sep 2024 22:56:25 -0400 Subject: [PATCH 4/6] feat: functions to convert keyset ID to and from u64 --- crates/cdk/src/nuts/nut02.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/cdk/src/nuts/nut02.rs b/crates/cdk/src/nuts/nut02.rs index 0923c341..e8f631ef 100644 --- a/crates/cdk/src/nuts/nut02.rs +++ b/crates/cdk/src/nuts/nut02.rs @@ -105,6 +105,20 @@ impl Id { id: bytes[1..].try_into()?, }) } + + /// [`Id`] to u64 + pub fn to_u64(&self) -> u64 { + let bytes = self.to_bytes(); + let mut array = [0u8; 8]; + array[..bytes.len()].copy_from_slice(&bytes); + u64::from_be_bytes(array) + } + + /// [`Id`] from u64 + pub fn from_u64(value: u64) -> Result { + let bytes = value.to_be_bytes(); + Self::from_bytes(&bytes) + } } impl TryFrom for u64 { From 90b69e0c360ef5f36dec2ecf5e295629247c8503 Mon Sep 17 00:00:00 2001 From: vnprc Date: Thu, 12 Sep 2024 11:25:08 -0400 Subject: [PATCH 5/6] feat: derive debug for mint struct --- crates/cdk/src/cdk_database/mod.rs | 3 ++- crates/cdk/src/mint/mod.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 33e3bd00..2a0c5498 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -2,6 +2,7 @@ #[cfg(any(feature = "wallet", feature = "mint"))] use std::collections::HashMap; +use std::fmt; use std::fmt::Debug; #[cfg(any(feature = "wallet", feature = "mint"))] @@ -169,7 +170,7 @@ pub trait WalletDatabase: Debug { /// Mint Database trait #[cfg(feature = "mint")] #[async_trait] -pub trait MintDatabase { +pub trait MintDatabase: fmt::Debug { /// Mint Database Error type Err: Into + From; diff --git a/crates/cdk/src/mint/mod.rs b/crates/cdk/src/mint/mod.rs index f09d076e..bc4d0a99 100644 --- a/crates/cdk/src/mint/mod.rs +++ b/crates/cdk/src/mint/mod.rs @@ -26,7 +26,7 @@ pub mod types; pub use types::{MeltQuote, MintQuote}; /// Cashu Mint -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Mint { /// Mint Url pub mint_url: MintUrl, From df467876da56d7aab95355721c63da4c40822473 Mon Sep 17 00:00:00 2001 From: vnprc Date: Thu, 12 Sep 2024 11:46:05 -0400 Subject: [PATCH 6/6] fix: add Debug supertrait to MintDatabase --- crates/cdk/src/cdk_database/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cdk/src/cdk_database/mod.rs b/crates/cdk/src/cdk_database/mod.rs index 2a0c5498..5f5ba521 100644 --- a/crates/cdk/src/cdk_database/mod.rs +++ b/crates/cdk/src/cdk_database/mod.rs @@ -172,7 +172,7 @@ pub trait WalletDatabase: Debug { #[async_trait] pub trait MintDatabase: fmt::Debug { /// Mint Database Error - type Err: Into + From; + type Err: Into + From + Debug; /// Add Active Keyset async fn set_active_keyset(&self, unit: CurrencyUnit, id: Id) -> Result<(), Self::Err>;