Browse Source

refactor: use TargetAmount

thesimplekid 10 months ago
parent
commit
0dce83bbb7

+ 39 - 7
bindings/cdk-js/src/wallet.rs

@@ -2,6 +2,7 @@ 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;
@@ -146,12 +147,20 @@ impl JsWallet {
     }
 
     #[wasm_bindgen(js_name = mint)]
-    pub async fn mint(&mut self, mint_url: String, quote_id: String) -> Result<JsAmount> {
+    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, &quote_id)
+            .mint(mint_url, &quote_id, target)
             .await
             .map_err(into_err)?
             .into())
@@ -192,12 +201,20 @@ impl JsWallet {
     }
 
     #[wasm_bindgen(js_name = melt)]
-    pub async fn melt(&mut self, mint_url: String, quote_id: String) -> Result<JsMelted> {
+    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, &quote_id)
+            .melt(&mint_url, &quote_id, target)
             .await
             .map_err(into_err)?;
 
@@ -216,12 +233,18 @@ impl JsWallet {
 
         Ok(self
             .inner
-            .receive(&encoded_token, None, signing_keys, preimages)
+            .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,
@@ -231,6 +254,7 @@ impl JsWallet {
         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(_)) => {
@@ -245,19 +269,23 @@ impl JsWallet {
 
         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),
-                None,
+                &target,
                 conditions,
             )
             .await
             .map_err(into_err)
     }
 
+    #[allow(clippy::too_many_arguments)]
     #[wasm_bindgen(js_name = swap)]
     pub async fn swap(
         &mut self,
@@ -267,6 +295,7 @@ impl JsWallet {
         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(_)) => {
@@ -283,13 +312,16 @@ impl JsWallet {
 
         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)),
-                None,
+                &target,
                 proofs,
                 conditions,
             )

+ 10 - 10
crates/cdk/src/amount.rs

@@ -24,18 +24,16 @@ impl Amount {
 
     /// Split into parts that are powers of two by target
     pub fn split_targeted(&self, target: &SplitTarget) -> Vec<Self> {
-        let mut parts = vec![];
-        let mut parts_total = Amount::ZERO;
-
-        match *target {
-            SplitTarget::None => {
-                parts = self.split();
-            }
+        let mut parts = match *target {
+            SplitTarget::None => self.split(),
             SplitTarget::Value(amount) => {
                 if self.le(&amount) {
                     return self.split();
                 }
 
+                let mut parts_total = Amount::ZERO;
+                let mut parts = Vec::new();
+
                 // The powers of two that are need to create target value
                 let parts_of_value = amount.split();
 
@@ -55,8 +53,10 @@ impl Amount {
                         }
                     }
                 }
+
+                parts
             }
-        }
+        };
 
         parts.sort();
         parts
@@ -68,10 +68,10 @@ impl Amount {
     Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize,
 )]
 pub enum SplitTarget {
-    /// Default target least amount of proofs
+    /// Default target; least amount of proofs
     #[default]
     None,
-    /// Tagrget amount for wallet to have most proofs that add up to value
+    /// Target amount for wallet to have most proofs that add up to value
     Value(Amount),
 }
 

+ 8 - 4
crates/cdk/src/nuts/nut00.rs

@@ -356,8 +356,12 @@ pub struct PreMintSecrets {
 
 impl PreMintSecrets {
     /// Outputs for speceifed amount with random secret
-    pub fn random(keyset_id: Id, amount: Amount) -> Result<Self, Error> {
-        let amount_split = amount.split();
+    pub fn random(
+        keyset_id: Id,
+        amount: Amount,
+        amount_split_target: &SplitTarget,
+    ) -> Result<Self, Error> {
+        let amount_split = amount.split_targeted(amount_split_target);
 
         let mut output = Vec::with_capacity(amount_split.len());
 
@@ -427,10 +431,10 @@ impl PreMintSecrets {
     pub fn with_conditions(
         keyset_id: Id,
         amount: Amount,
-        amount_split_target: SplitTarget,
+        amount_split_target: &SplitTarget,
         conditions: SpendingConditions,
     ) -> Result<Self, Error> {
-        let amount_split = amount.split_targeted(&amount_split_target);
+        let amount_split = amount.split_targeted(amount_split_target);
 
         let mut output = Vec::with_capacity(amount_split.len());
 

+ 3 - 1
crates/cdk/src/nuts/nut13.rs

@@ -7,6 +7,7 @@ use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
 use super::nut00::{BlindedMessage, PreMint, PreMintSecrets};
 use super::nut01::SecretKey;
 use super::nut02::Id;
+use crate::amount::SplitTarget;
 use crate::dhke::blind_message;
 use crate::error::Error;
 use crate::secret::Secret;
@@ -46,12 +47,13 @@ impl PreMintSecrets {
         xpriv: ExtendedPrivKey,
         amount: Amount,
         zero_amount: bool,
+        amount_split_target: &SplitTarget,
     ) -> Result<Self, Error> {
         let mut pre_mint_secrets = PreMintSecrets::default();
 
         let mut counter = counter;
 
-        for amount in amount.split() {
+        for amount in amount.split_targeted(amount_split_target) {
             let secret = Secret::from_xpriv(xpriv, keyset_id, counter)?;
             let blinding_factor = SecretKey::from_xpriv(xpriv, keyset_id, counter)?;
 

+ 34 - 12
crates/cdk/src/wallet.rs

@@ -444,7 +444,9 @@ impl Wallet {
                 .await?;
 
             if mint_quote_response.paid {
-                let amount = self.mint(mint_quote.mint_url, &mint_quote.id).await?;
+                let amount = self
+                    .mint(mint_quote.mint_url, &mint_quote.id, SplitTarget::default())
+                    .await?;
                 total_amount += amount;
             } else if mint_quote.expiry.le(&unix_time()) {
                 self.localstore.remove_mint_quote(&mint_quote.id).await?;
@@ -511,7 +513,12 @@ impl Wallet {
 
     /// Mint
     #[instrument(skip(self, quote_id), fields(mint_url = %mint_url))]
-    pub async fn mint(&self, mint_url: UncheckedUrl, quote_id: &str) -> Result<Amount, Error> {
+    pub async fn mint(
+        &self,
+        mint_url: UncheckedUrl,
+        quote_id: &str,
+        amount_split_target: SplitTarget,
+    ) -> Result<Amount, Error> {
         // Check that mint is in store of mints
         if self.localstore.get_mint(mint_url.clone()).await?.is_none() {
             self.add_mint(mint_url.clone()).await?;
@@ -544,6 +551,7 @@ impl Wallet {
             self.xpriv,
             quote_info.amount,
             false,
+            &amount_split_target,
         )?;
 
         let mint_res = self
@@ -599,7 +607,7 @@ impl Wallet {
         mint_url: &UncheckedUrl,
         unit: &CurrencyUnit,
         amount: Option<Amount>,
-        amount_split_target: Option<SplitTarget>,
+        amount_split_target: &SplitTarget,
         input_proofs: Proofs,
         spending_conditions: Option<SpendingConditions>,
     ) -> Result<Option<Proofs>, Error> {
@@ -706,7 +714,7 @@ impl Wallet {
         mint_url: &UncheckedUrl,
         unit: &CurrencyUnit,
         amount: Option<Amount>,
-        amount_split_target: Option<SplitTarget>,
+        amount_split_target: &SplitTarget,
         proofs: Proofs,
         spending_conditions: Option<SpendingConditions>,
     ) -> Result<PreSwap, Error> {
@@ -733,13 +741,14 @@ impl Wallet {
                     self.xpriv,
                     change_amount,
                     false,
+                    amount_split_target,
                 )?;
 
                 (
                     PreMintSecrets::with_conditions(
                         active_keyset_id,
                         desired_amount,
-                        amount_split_target.unwrap_or_default(),
+                        amount_split_target,
                         conditions,
                     )?,
                     change_premint_secrets,
@@ -759,6 +768,7 @@ impl Wallet {
                     self.xpriv,
                     desired_amount,
                     false,
+                    amount_split_target,
                 )?;
 
                 count += premint_secrets.len() as u32;
@@ -769,6 +779,7 @@ impl Wallet {
                     self.xpriv,
                     change_amount,
                     false,
+                    amount_split_target,
                 )?;
 
                 (premint_secrets, change_premint_secrets)
@@ -796,7 +807,7 @@ impl Wallet {
         unit: &CurrencyUnit,
         memo: Option<String>,
         amount: Amount,
-        amount_split_target: Option<SplitTarget>,
+        amount_split_target: &SplitTarget,
         conditions: Option<SpendingConditions>,
     ) -> Result<String, Error> {
         let input_proofs = self.select_proofs(mint_url.clone(), unit, amount).await?;
@@ -955,7 +966,12 @@ impl Wallet {
 
     /// Melt
     #[instrument(skip(self, quote_id), fields(mint_url = %mint_url))]
-    pub async fn melt(&mut self, mint_url: &UncheckedUrl, quote_id: &str) -> Result<Melted, Error> {
+    pub async fn melt(
+        &mut self,
+        mint_url: &UncheckedUrl,
+        quote_id: &str,
+        amount_split_target: SplitTarget,
+    ) -> Result<Melted, Error> {
         let quote_info = self.localstore.get_melt_quote(quote_id).await?;
 
         let quote_info = if let Some(quote) = quote_info {
@@ -983,8 +999,14 @@ impl Wallet {
 
         let count = count.map_or(0, |c| c + 1);
 
-        let premint_secrets =
-            PreMintSecrets::from_xpriv(active_keyset_id, count, self.xpriv, proofs_amount, true)?;
+        let premint_secrets = PreMintSecrets::from_xpriv(
+            active_keyset_id,
+            count,
+            self.xpriv,
+            proofs_amount,
+            true,
+            &amount_split_target,
+        )?;
 
         let melt_response = self
             .client
@@ -1045,7 +1067,7 @@ impl Wallet {
     pub async fn receive(
         &self,
         encoded_token: &str,
-        amount_split_target: Option<SplitTarget>,
+        amount_split_target: &SplitTarget,
         signing_keys: Option<Vec<SecretKey>>,
         preimages: Option<Vec<String>>,
     ) -> Result<Amount, Error> {
@@ -1198,7 +1220,7 @@ impl Wallet {
     pub async fn nostr_receive(
         &self,
         nostr_signing_key: SecretKey,
-        amount_split_target: Option<SplitTarget>,
+        amount_split_target: SplitTarget,
     ) -> Result<Amount, Error> {
         use nostr_sdk::{Keys, Kind};
 
@@ -1247,7 +1269,7 @@ impl Wallet {
             match self
                 .receive(
                     token,
-                    amount_split_target,
+                    &amount_split_target,
                     Some(vec![nostr_signing_key.clone()]),
                     None,
                 )